Professional game controls with Mouse and KeyBoard

Hi there everyone. I was wondering if anybody knows how “Descent like” controls work with OpenGL. I can sort of move around in my 3D world with the mouse and keyboard but it just doesn’t work right. Its like everytime I point the camera, say left for example, and hit the up arrow key to go forward in the new direction I end up rolling a bit. And continuous motion and changing of direction is really problematic. I usually end up upside down as I fly. I think the problem is how I’m handling the passive mouse input, but I’m not sure. Any suggestions guys?

I’m not sure either.
Infact how can anyone be sure if you don’t even bother to post some code which shows what you are doing?

Sorry for not posting my code. I had a rather unpleasant experience after posting my code a while ago. Anyhow, I think this is all the relevant code:

<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>



double a[3] = {0, 0, -1}, e[3] = {0, 0, 0}, u[3] = {1, 0, 0}, v[3] = {0, 1, 0}, n[3] = {0, 0, 1};
int curX = 512, curY = 384; 

void moveCamera(char key)
{
   double xTemp, yTemp, zTemp, a1 = 0.8, a2;

   if(key == 'f')
   {
     e[0] = e[0] - a1 * n[0];
     e[1] = e[1] - a1 * n[1];
     e[2] = e[2] - a1 * n[2]; 
   }
   else if(key == 'b')
   {
     e[0] = e[0] + a1 * n[0];
     e[1] = e[1] + a1 * n[1];
     e[2] = e[2] + a1 * n[2];
   }
   else if(key == 'r')
   {
     e[0] = e[0] + a1 * u[0];
     e[1] = e[1] + a1 * u[1];
     e[2] = e[2] + a1 * u[2];
   }
   else if(key == 'l')
   {
     e[0] = e[0] - a1 * u[0];
     e[1] = e[1] - a1 * u[1];
     e[2] = e[2] - a1 * u[2];
   }
   else if(key == 'L' || key == 'a')
   {
     xTemp = u[0];
     yTemp = u[1];
     zTemp = u[2];

     if(key == 'L')
       a2 = 0.01;
     else
       a2 = 0.1;

     u[0] =  cos(a2) * xTemp -  sin(a2) * n[0];
     u[1] =  cos(a2) * yTemp -  sin(a2) * n[1];
     u[2] =  cos(a2) * zTemp -  sin(a2) * n[2];
     n[0] =  sin(a2) * xTemp +  cos(a2) * n[0];
     n[1] =  sin(a2) * yTemp +  cos(a2) * n[1];
     n[2] =  sin(a2) * zTemp +  cos(a2) * n[2];
   }
   else if(key == 'R' || key == 'd')
   {
     xTemp = u[0];
     yTemp = u[1];
     zTemp = u[2];

     if(key == 'R')
       a2 = 0.01;
     else
       a2 = 0.1;

     u[0] =  cos(-a2) * xTemp -  sin(-a2) * n[0];
     u[1] =  cos(-a2) * yTemp -  sin(-a2) * n[1];
     u[2] =  cos(-a2) * zTemp -  sin(-a2) * n[2];
     n[0] =  sin(-a2) * xTemp +  cos(-a2) * n[0];
     n[1] =  sin(-a2) * yTemp +  cos(-a2) * n[1];
     n[2] =  sin(-a2) * zTemp +  cos(-a2) * n[2];
   }
   else if(key == 'U' || key == 's')
   {
     xTemp = v[0];
     yTemp = v[1];
     zTemp = v[2];

     if(key == 'U')
       a2 = 0.01;
     else
       a2 = 0.1;

     v[0] =  cos(a2) * xTemp -  sin(a2) * n[0];
     v[1] =  cos(a2) * yTemp -  sin(a2) * n[1];
     v[2] =  cos(a2) * zTemp -  sin(a2) * n[2];
     n[0] =  sin(a2) * xTemp +  cos(a2) * n[0];
     n[1] =  sin(a2) * yTemp +  cos(a2) * n[1];
     n[2] =  sin(a2) * zTemp +  cos(a2) * n[2];
   }
   else if(key == 'D' || key == 'w')
   {
     xTemp = v[0];
     yTemp = v[1];
     zTemp = v[2];

     if(key == 'D')
       a2 = 0.01;
     else
       a2 = 0.1;

     v[0] = cos(-a2) * xTemp - sin(-a2) * n[0];
     v[1] = cos(-a2) * yTemp - sin(-a2) * n[1];
     v[2] = cos(-a2) * zTemp - sin(-a2) * n[2];
     n[0] = sin(-a2) * xTemp + cos(-a2) * n[0];
     n[1] = sin(-a2) * yTemp + cos(-a2) * n[1];
     n[2] = sin(-a2) * zTemp + cos(-a2) * n[2];
   }  

   a[0] = e[0] - n[0];
   a[1] = e[1] - n[1];
   a[2] = e[2] - n[2];
 
   
}

void handleMouse(int x, int y)
{
    
   if(x > curX)
     moveCamera('R');
   else if(x < curX)
     moveCamera('L');
   
   if(y > curY)
     moveCamera('U');
   else if(y < curY)
     moveCamera('D');
    
   curX = x;     
   curY = y;

   if(curX > 900 || curX < 1 || curY > 660 || curY < 1)
    glutWarpPointer(512, 384);
   
}

void handleInput(int key, int x, int y)
{

  switch(key)
  {
     case GLUT_KEY_UP:
     moveCamera('f');
     break;

     case GLUT_KEY_DOWN:
     moveCamera('b');
     break; 

     case GLUT_KEY_LEFT:
     moveCamera('l');
     break;

     case GLUT_KEY_RIGHT:
     moveCamera('r');
     break;
  }

}

//Called when a key is pressed
void handleKeypress(unsigned char key, int x, int y) {
    

	switch (key) {
		case 27: //Escape key
        glutLeaveGameMode();
		exit(0);
        break;
       
        case 'd':
        moveCamera('d');
        break;

        case 'a':
        moveCamera('a');
        break;

        case 'w':
        moveCamera('w');
        break;

        case 's':
        moveCamera('s');
        break;
    }
}

void drawScene()
{
   .......
   gluLookAt(e[0], e[1], e[2], a[0], a[1], a[2], v[0], v[1], v[2]);
   ........
   //draw stuff and swap
}
 

[/QUOTE]</div>

Sorry buddy. It may as well be written in Assemby language for all the good posting the code has done.
The problem is the code is so low level with multiplications to unknown variables like ‘u’ and no comments.
How on Earth is anyone to make anything of this?

Sorry I wasted your time BionicBytes. I of course could go through it and comment it but it sounds as if you’re annoyed to the point you don’t want to help anymore.

Vindy,
BionicBytes has a point although he/she could have been a little nicer about it. In order for people to help you, good programming style and well commented code goes a long way. The key to prevent your horizon from rolling is to not change the “Up” direction. Please compare your code to the following code. Please forgive the lack of tabs, I don’t know how to include the file the way you did and this web site removes white space when posting.

//======Source Code====================================================================

#define PI 3.1415927f

float Eye_x, Eye_y, Eye_z, LookAt_x, LookAt_y, LookAt_z, LookUp_x, LookUp_y, LookUp_z;

void Setup() {
Eye_x = 0; // At the origin slightly above the horizon
Eye_y = 0;
Eye_z = 12;

LookAt_x = 10; // Looking north-east horizontally 
LookAt_y = 10;
LookAt_z = 12; 

LookUp_x = 0;  // Never change to maintain horizon with Z-direction up
LookUp_y = 0;
LookUp_z = 1;

}

void KeyboardFunction(unsigned char key, int x, int y)
{
float d_x, d_y, d_z, d_xy, d_xyz, theta_xy, theta_xyz, LinearStep, AngularStep;

LinearStep = 1.0;

d_x = LookAt_x - Eye_x; // x distance
d_y = LookAt_y - Eye_y; // y distance
d_z = LookAt_z - Eye_z; // z distance

d_xy = pow( d_x * d_x + d_y * d_y, 0.5); // horizonal 2D distance
d_xyz = pow( d_x * d_x + d_y * d_y + d_z * d_z, 0.5); // 3D distance

AngularStep = atan(LinearStep / d_xy) * 180.0 / PI;

// calculate horizontal angle (left/right)
if (d_x == 0) // avoid division by 0
{
	if (d_y &lt; 0)
		theta_xy = 270;
	else 
		theta_xy = 90;
}
else
{
	theta_xy = atan(d_y / d_x) * 180.0 / PI;
	if (d_x &lt; 0)
		theta_xy += 180;
	if (theta_xy &lt; 0)
		theta_xy += 360;
}

// calculate verticle angle (angle with the horizon, limited to +/- 90 degrees)
theta_xyz = atan(d_z / d_xy) * 180 / PI;

switch(key)
{
case 'f': // move forward horizontally by shifting Eye toward LookAt (and shifting LookAt same distance)
	Eye_x    += LinearStep * cos(theta_xy * PI / 180.0); 
	Eye_y    += LinearStep * sin(theta_xy * PI / 180.0);
	LookAt_x += LinearStep * cos(theta_xy * PI / 180.0);
	LookAt_y += LinearStep * sin(theta_xy * PI / 180.0);
	break;

case 'b': // move back horizontally by shifting Eye away from LookAt (and shifting LookAt same distance)
	Eye_x    -= LinearStep * cos(theta_xy * PI / 180.0); 
	Eye_y    -= LinearStep * sin(theta_xy * PI / 180.0);
	LookAt_x -= LinearStep * cos(theta_xy * PI / 180.0);
	LookAt_y -= LinearStep * sin(theta_xy * PI / 180.0);
	break;

case 'r': // move right horizontally by shifting Eye - 90 degrees from LookAt (and shifting LookAt same distance)
	Eye_x    += LinearStep * cos((theta_xy-90.0) * PI / 180.0); 
	Eye_y    += LinearStep * sin((theta_xy-90.0) * PI / 180.0);
	LookAt_x += LinearStep * cos((theta_xy-90.0) * PI / 180.0);
	LookAt_y += LinearStep * sin((theta_xy-90.0) * PI / 180.0);
	break;

case 'l': // move left horizontally by shifting Eye + 90 degrees from LookAt (and shifting LookAt same distance)
	Eye_x    += LinearStep * cos((theta_xy+90.0) * PI / 180.0); 
	Eye_y    += LinearStep * sin((theta_xy+90.0) * PI / 180.0);
	LookAt_x += LinearStep * cos((theta_xy+90.0) * PI / 180.0);
	LookAt_y += LinearStep * sin((theta_xy+90.0) * PI / 180.0);
	break;

case 'u': // move up vertically by shifting Eye up Z-axis (and shifting LookAt same distance)
	Eye_z    += LinearStep;
	LookAt_z += LinearStep;
	break;

case 'd': // move down vertically by shifting Eye down Z-axis (and shifting LookAt same distance)
	Eye_z    -= LinearStep;
	LookAt_z -= LinearStep;
	break;

case 'R': // rotate right by changing angle from Eye to LookAt - degrees horizontally
	LookAt_x  = Eye_x + d_xy * cos((theta_xy - AngularStep) * PI / 180.0);
	LookAt_y  = Eye_y + d_xy * sin((theta_xy - AngularStep) * PI / 180.0);
	break;

case 'L': // rotate left by changing angle from Eye to LookAt + degrees horizontally
	LookAt_x  = Eye_x + d_xy * cos((theta_xy + AngularStep) * PI / 180.0);
	LookAt_y  = Eye_y + d_xy * sin((theta_xy + AngularStep) * PI / 180.0);
	break;

case 'U': // rotate up by changing angle from Eye to LookAt + degrees vertically (do not allow straight up)
	if (theta_xyz + AngularStep &lt; 90.0)
	{
		LookAt_x  = Eye_x + d_xyz * cos((theta_xyz + AngularStep) * PI / 180.0) * cos(theta_xy * PI / 180.0);
		LookAt_y  = Eye_y + d_xyz * cos((theta_xyz + AngularStep) * PI / 180.0) * sin(theta_xy * PI / 180.0);
		LookAt_z  = Eye_z + d_xyz * sin((theta_xyz + AngularStep) * PI / 180.0);
	}
	break;

case 'D': // rotate up by changing angle from Eye to LookAt - degrees vertically (do not allow straight down)
	if (theta_xyz - AngularStep &gt; -90.0)
	{
		LookAt_x  = Eye_x + d_xyz * cos((theta_xyz - AngularStep) * PI / 180.0) * cos(theta_xy * PI / 180.0);
		LookAt_y  = Eye_y + d_xyz * cos((theta_xyz - AngularStep) * PI / 180.0) * sin(theta_xy * PI / 180.0);
		LookAt_z  = Eye_z + d_xyz * sin((theta_xyz - AngularStep) * PI / 180.0);
	}
	break;
}

glutPostRedisplay();

}

void RenderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
gluLookAt(Eye_x, Eye_y, Eye_z, LookAt_x, LookAt_y, LookAt_z, LookUp_x, LookUp_y, LookUp_z);

glPushMatrix();
Draw();
glPopMatrix();

glutSwapBuffers();

}

One copy / paste error in my comments. Case ‘D’ is “rotate down” (the code is correct)