Moving in 3D

Started by
4 comments, last by NineYearCycle 15 years, 9 months ago
Hi, I have a 3D world and want to move around in it. If the user presses the left or right arrow keys they rotate left or right by 4 degrees. If they press up they start moving forward. If they press it again their speed increases (and opposite for back arrow). I wrote the following in C++ and OpenGL. The code works perfectly as long as you never rotate while moving. If you stop and rotate and then start moving, the camera "moves" correctly down the line of sight. My knowledge of linear algebra is minimal and I am sure that is where my problem is. Also, when the program first loads the user is looking in the +Y direction. Here is my function that draws the scene every frame:

void display(void)
{             
     //Calculate current altitude  
     altitude = (altitude + -1*oz);           
               
     glutSetWindow(window3D);
     glTranslatef(ox,oy,oz); //Translate to a new position (if updated)   

     //Keep track of current acft position
     posx = posx + ox;
     posy = posy + oy;
     posz = posz + oz;
       
     glClearColor(0, 0, 1, 0.0);  //Set Sky color
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);             

     //Draw ground and orientate correctly
     glPushAttrib(GL_ALL_ATTRIB_BITS);                                                                      
     glPushMatrix();     
        glRotatef(90,1,0,0);   
        glScalef(worldx+10,1,worldy+10);
        glBegin(GL_QUADS);               
            glColor3f(wc1, wc2, wc3);        //Set color of ground
            glVertex3f( 0.5f,-0.5f, 0.5f);	
            glVertex3f(-0.5f,-0.5f, 0.5f);	
            glVertex3f(-0.5f,-0.5f,-0.5f);	
            glVertex3f( 0.5f,-0.5f,-0.5f);			
        glEnd();
     glPopAttrib();                      
     glPopMatrix();                     
     
     drawObjects();       //Call function to draw world
     glutSwapBuffers();       
}

Here is my code when the user presses a key:


//Right = posive
void rotateMe(int direction)
{
     glutSetWindow(window3D);     
     arrowAngle = (arrowAngle + (direction*5));
     glTranslatef(-posx,-posy,-posz); 
     glRotatef(direction*5,0,0,1);
     glTranslatef(posx,posy,posz);  
}//function

//Function that moves user
//Direction specifies forward or backwards
//Back    = negative
//Forward = posive
void moveMe(int direction)
{
     glutSetWindow(window3D);     
     rad = arrowAngle * (3.14/180);      //Convert to radians
     ox = (ox + direction*sin(rad));
     oy = (oy + direction*cos(rad));          
}//function

//Function to process special keys    
void specialKeyboard(int key, int kx, int ky)
{
 /*  LEGEND
 
     Page Up       -  Increase altitude
     Page Down     -  Decrease altitude
     Left Arrow    - Turn Left
     Right Arrow   - Turn Right
     Forward Arrow - Move forward
     Back Arrow    - Move backward
 */      
     switch (key)
     {
            case GLUT_KEY_PAGE_DOWN :
                 //check to ensure rate of climb is not too steep
                 if ((oz < maxclimb))  
                 {
                    counter--;                 
                    oz = oz + 0.3;                                                     
                 }
                 break;

            case GLUT_KEY_PAGE_UP :                 
                 //check to ensure rate of climb is not too steep
                 if ((oz > -1*maxclimb))                   
                 {
                    counter++;
                    oz = oz - 0.3;
                 }
                 break;

            case GLUT_KEY_LEFT :                    
                 rotateMe(-1);                                                                                                                   
                 break;

            case GLUT_KEY_RIGHT : 
                 rotateMe(+1);   
                 break;
 
            case GLUT_KEY_UP  :                                      
                 moveMe(-1);
                 break;

            case GLUT_KEY_DOWN :  
                 moveMe(+1);
                 break;                          
     } //Switch
  if (counter == 0)
     oz = 0;
} //Function

Advertisement
I don't think it's a good idea to immediately do rotations when pressing a key. (i.e. the rotations/translations in your moveMe and rotateMe functions you call after a key has been pressed)

From just briefly looking at the code I can't see why it isn't working as it should. But I suggest you take a look at Lesson 10 from NeHe. There moving in a 3D world is handled.
Goodluck!

I ended up getting it working. Can't remember off the top of my head what I had to change.

Why do you suggest not rotating immediately?

Thanks for the input
Quote:Original post by mbanghart
Why do you suggest not rotating immediately?


One things that can happen in the case of using Glut is that you might find that a turn rate of 1 is fine on your computer but far too fast on someone elses or too slow on anothers because of the varying framerate of the application.

Its common to first "gather" the input into your app and then "handle" the inputs later in another function. This allows you to gather all of the systems inputs, mouse, keyboard, joystick/pad, Wii-mote (i.e. whatever) and then apply them perhaps with the frame time so that you have something like:
// your examplemove( 1 )// frame-rate independent versionmove( 1 * lastTimeStep );


The advantage of gathering input information is that you can workout if keys have been pressed, held, or released which Glut doesn't tell you but can be helpful for knowing how to react. An example would be that when a key is pressed you begin to turn slowly, but if the key is held for more than a certain amount of time the rate of turn should be faster. In your current system the user will have to press the key repeatedly to turn as it only catchs "key-presses". Actually that's a slight lie, you'll actually get TWO hits of those calls because it will hit once for the press and once for the release of the key! Just another reason to gather and then process the inputs later.

edit: also if you've gathered your input then you can handle it multiple times, for example you might run forward if 'w' is pressed, and jump if 'space' is pressed, but if you only handle the input at the instant that each seperate key is pressed you won't know that 'w' + 'space' are pressed so you can't do a "long-forward-jump" for example.

I'm getting quite tired Sso I hope that above makes some sense. If not PM me and I'll reply here tomorrow. G'night.

Andy

PS: please use source tags when posting source code :)

"Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile"

"Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgement difficult."

Makes sense. Wouldn't a timer function ensure that your frame rate is always the same regardless of the machine?
Quote:Original post by mbanghart
Makes sense. Wouldn't a timer function ensure that your frame rate is always the same regardless of the machine?


Yes, that essentially what I'm advocating in modifying the turn/move rate by the size of the last time step ;) but it makes sense to do it in one place rather than many. You can always fudge a way around things but it's better to do things right one and not have to maintain them laboriously if they exist in many forms scattered around in different functions.

Andy

"Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile"

"Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgement difficult."

This topic is closed to new replies.

Advertisement