PDA

View Full Version : Taking input while inside while loop



biribiri
10-26-2013, 04:27 AM
Basically, I am trying to make a brick breaker game using opengl.
What I am stuck with is the fact, that my functions for all different objects to be drawn gets called inside a while(1) loop, but at the same time I need inputs from my keyboard to be registered. But my glutkeyboardfunc never gets called because of the preceeding infinte while loop. What logic/method can I use to solve this? Thank you.
Here's the code if required:



using namespace std;
#include <iostream>
#include <GL/glut.h>
#include <cstdio>
#include <cmath>
#include <vector>
#define rad 10
#define noblock 20
float DEG2RAD = 3.14159/180;
float xmin=-20, ymin=-200, xmax=70, ymax=-180,cx=35,cy=-170;
int t=1,r=1;
float cxmin,cxmax,cymin,cymax;
void delay(int n)
{
clock_t t=n+clock();
while(t>clock());
}
void dcirc(float x, float y)
{
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINE_LOOP);
for (int i=0; i < 360; i++)
{
float degInRad = i*DEG2RAD;
glVertex2f(x+cos(degInRad)*rad,y+sin(degInRad)*rad );
}

glEnd();
glFlush();
}
int hit[20]={0};
vector<float> x1,x2,ay1,y2;
void box()
{
glColor3f(0.0,1.0,0.0);
float lx1=-160,ly1=150,lx2=-130,ly2=170;
for(int i=0;i<noblock;i++)
{
if(hit[i]==0)
{
glBegin(GL_LINE_LOOP);
glVertex2i(lx1,ly1);
glVertex2i(lx2,ly1);
glVertex2i(lx2,ly2);
glVertex2i(lx1,ly2);
glEnd();
x1.push_back(lx1);
x2.push_back(lx2);
ay1.push_back(ly1);
y2.push_back(ly2);
lx1+=30;
lx2+=30;
if(i==9)
{
lx1=-160;lx2=-130;ly1=130;ly2=150;
}
}
else
{
lx1+=30;
lx2+=30;
if(i==9)
{
lx1=-160;lx2=-130;ly1=130;ly2=150;
}
}
}
glFlush();
}
void dbox()
{
glColor3f(0.0,0.0,1.0);
glBegin(GL_LINE_LOOP);
glVertex2i(xmin,ymin);
glVertex2i(xmax,ymin);
glVertex2i(xmax,ymax);
glVertex2i(xmin,ymax);
glEnd();
glFlush();
}
void mc()
{
if(cx+rad>200){r=0;}
if(cx-rad<-200){r=1;}
if(cy+rad>200){t=0;}
if(cx<=xmax&&cx>=xmin&&cy==rad-180) {t=1;}
if(cy-rad==-200) t=1;//exit(0);
for(int i=0;i<noblock;i++)
{
if(((cy+rad)==ay1[i])&&(hit[i]==0)&&(cx<=x2[i])&&(cx>=x1[i]))
{
hit[i]=1;
t=0;
}
else if(((cy-rad)==y2[i])&&(hit[i]==0)&&(cx<=x2[i])&&(cx>=x1[i]))
{
hit[i]=1;
t=1;
}
else if(((cx-rad)==x2[i])&&(hit[i]==0)&&(cy<=y2[i])&&(cy>=ay1[i]))
{
hit[i]=1;
r=1;
}
else if(((cx+rad)==x1[i])&&(hit[i]==0)&&(cy<=y2[i])&&(cy>=ay1[i]))
{
hit[i]=1;
r=0;
}
}
if(r==0) {cx--;}
if(r==1) {cx++;}
if(t==0) {cy--;}
if(t==1) {cy++;}
dcirc(cx,cy);
delay(1);
}
void show()
{
glClear(GL_COLOR_BUFFER_BIT);
dbox();
box();
mc();
}
void display()
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
dbox();
while(1) show();
glFlush();
}
void myKey(unsigned char key, int x, int y)
{
glClear(GL_COLOR_BUFFER_BIT);
if(key=='l')
{
xmax+=20;
xmin+=20;
}
else if(key=='k')
{
xmax-=20;
xmin-=20;
}
if(xmax>=200)
{
xmax=200;
xmin=130;
}
else if(xmin<=-200)
{
xmin=-200;
xmax=-130;
}
show();
}
void myInit(void)
{
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-200,200,-200,200);
}
int main(int argc,char** argv)
{
char p;
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(600,600);
glutInitWindowPosition(0,0);
glutCreateWindow("simple");
myInit();
glutDisplayFunc(&display);
glutKeyboardFunc(myKey);
glutMainLoop();
}

carsten neumann
10-26-2013, 05:28 AM
You need to structure things a bit differently. Your glutDisplayFunc should only draw a single frame (that allows the other callbacks, like the one for keyboard input to run as well) - think of it as drawing a snapshot of your "scene" at a fixed point in time.
Since there are things in your game that will move continuously, you should register a glutIdleFunc that just calls glutPostRedisplay(). That call tells glut that something in your game has changed and a new frame needs to be drawn. Your display function then has two tasks: first compute new positions for all objects that move (or other things that happen over time, e.g. animations) then draw things at their new positions/in their new state (sometimes these two steps can be combined - depends on what is most convenient). In order to make your game run independent of the CPU/GPU speed you can use e.g. glutGet(GLUT_ELAPSED_TIME) and calculate the amount objects move based on how much time since the last frame has elapsed (and the objects velocity of course); you can also keep that as a second step, if it otherwise gets too complicated.
In terms of structuring your code you may want to introduce a couple of structs that hold variables that belong together, e.g.:


struct Box
{
GLfloat position[2];
// type of box?
// size of box - if it varies? ...
};

std::vector<Box> boxes;


Similar for other "objects" in your game like the paddle, walls, the ball, etc. Please note that the latter mostly goes into general (game) programming, so questions about these aspects my be better directed at a different forum.

biribiri
10-26-2013, 06:43 AM
Thanks a lot! I looked up how to use glutIdleFunc() and glutPostRedisplay() and was able to solve the issues I had my with my code.

Also sorry, I didn't look around enough and thought this would be best place to post it to. If an admin can move it, well and good.

Thanks a lot again.

GClements
10-26-2013, 12:50 PM
you should register a glutIdleFunc that just calls glutPostRedisplay().
I'd suggest using glutTimerFunc() instead. Using an idle function can result in 100% CPU usage.