hi everyone,
am quite new to graphics.am tryin to write a car game.i jus wanted to know how to use special keys(like arrow keys n function keys as inputs).can anyone help me?

Recommended Answers

All 5 Replies

I've used them in a Snake game. I don't remember exactly but something like #77... :?: Check the ASCII code. You'll certainl find them there :)

hay if ur using the win32 API then use vertical keys like VK_UP so ur code will look like this:

LRESULT CALLBACK MessageHandler(HWND hwnd, UINT message, WPARAM wparam,
                                                 LPARAM lparam)
{
 switch(message)
 {
   ....
   case WM_KEYDOWN:
    if(wparam == VK_UP) keyUp = true ;
    if(wparam == VK_DOWN) keyDown = true ;
   break ;
  
   case WM_KEYUP:
     if(wparam == VK_UP) keyUp = false ;
     if(wparam == VK_DOWN) keyDown == false ;
   break ;
 ...
 }
 ...
}

Game Development 101—Animation, Input and Falling Blocks of Terro

I know, I know. Last month I said I'd cover animation and user input this month, and that I'd have a (pseudo) complete game ready for you this month. Well, this time I actually do, so no worries. Before we dive into the code, however, I wanted to make note of a couple things:

First, Techtrax is taking a couple of months vacation over the summer, but fear not! I will post several tutorials on my website during this time. Aside from my new stuff, in this section you'll also be able to find all of my articles that I have written for the e-zine, and in the future I will post demos and source code there as well (for now, they're kinda scattered about the internet from the various webspaces I've had).

Second, I've decided to forego the DirectX tutorials for now. Let's be honest - all I'm really doing with those is rehashing Microsoft's excellent tutorials distributed with the SDK, and based on the advice of several individuals I've decided to come back to those when I have a bit more practice. So, if you're here for DirectX programming, I will be covering that, but it'll be a bit down the road (definitely not in this article).

Finally, before we start, if you happen to make something cool using the stuff I've written about in these articles, drop me a line and I'll either post screenshots on my website or I'll provide a link. We're all learning here, and the best way to get advice is to get your stuff seen. So just drop me a line at the e-mail in my author bio, and I'll see what I can do.

Framerate Animation

Let's cover the more crucial thing first - animation. Now I'm not talking model animation or anything like that, though you can probably emulate that with some of the code I'll present here - I'm talking more about a graphics loop, enabling movement of sprites across the screen. Basically, what we'll be covering this month is animating the program, rather than just a part of it (or traditional animation). We'll discuss framerates, primarily, and touch on GLUT's methods available for drawing frames.

Now there are several approaches to generating a framerate. One we've already seen:

void draw(){

glutSwapBuffers();
glutPostRedisplay();

}

This generates a framerate that is as fast as the computer can flip up the images. This is ok to use if you are using other factors to control your program (such as an independent time-tracking method), but in general if you've got something moving on the screen this approach makes it much more challenging to control. Great for an MS Paint clone, bad for Contra.

To provide us with an alternative, we have to introduce a new function - the glut timer function. The glut timer function is a registerable callback function that is called after a given number of milliseconds, and allows you to pass a value between calls. What this gives us is a means of creating a static frame rate in our programs. The prototype for a typical glut timer function is:

void myTimer(int value);

and to use the timer function, we insert the following line into the main function and at the end of the timer function itself:

glutTimerFunc(1000/60,myTimer,x);

This tells Glut to call the myTimer function after 1000/60 milliseconds has passed, and to give it the value X as a parameter. X can be whatever you want, and can be used in any manner you choose. So, by sticking this into the main function before the glutMainLoop() call, we effectively start the program (thus, this call should be one of the last you make before starting the program loop) at that point, and then we create a loop that runs as often as we choose by putting this at the end of the timer function. This is known as a static framerate; in this example, I've chosen a static framerate for my program of 60.

To make this actually mean something to the program, we take our glutPostRedisplay() (remember that this tells the program when to draw) and stick it in the timer function. And there you have it - you now have a program that draws 60 times (or less, depending on the quality of your machine) a second. Here is the example timer function that implements this:

void myTimer(int value){

glutPostRedisplay();
glutTimerFunc(1000/60, myTimer, 1);

}

Looks simple, doesn't it? Well that's for a good reason - it is. The call to glutPostRedisplay() tells the program to draw itself every time this function is called, and the glutTimerFunc() call resets the timer, calling the function 60 times every second. In order to generate the looping effect, this call is necessary, as each call to glutTimerFunc only calls the function once.

This timer function also turns out to be a handy place to run our game's logic rules - a few programming tricks can help us to run the logic as often as we want (if, for example, you want to drop the block by a line every second, you can play some tricks with either the value parameter or global variables to have this function run the logic module after a second has passed). Furthermore, this function is crucial in the third type of framerate specification.

The third type of framerate specification is one that is specified programatically. Something like a combination of "As fast as we can" and "as often as we want," this method can be used to specify a programatically-varied framerate. Basically, this allows those with better video cards to get a more visually stimulating experience, while still preserving as much of the flow as possible.

Now I have to admit, I'm not as familiar with this method as the other two, but the leap of logic to get there isn't all that large to begin with. Basically, you use C++'s time library to obtain a reference to the system clock (the number of milliseconds), which you then post against a target frame rate. This way, if you're doing some intense 3D stuff, and your computer can't really handle it, you can still roughly regulate the motion that takes place on the screen by multiplying the desired motion per frame by the ratio of target frames/actual frames. Sounds complicated? Again, it isn't all that challenging, but it does take some extra work that, to be honest, doesn't really come into play until later in the series, so I'm just going to leave this on the back burner for now. If you really can't wait to learn about this, there's a decent article on gamedev.net that touches on the subject, specifically relating it to sprite movement in a game environment. Give that a browse, and play with the code a bit - should sate your appetite for a little while.

Since all we're doing right now is 2D work, the first two methods are obviously less of a programming headache. For the game I've programmed for this article, I've actually cheated and used a slight hybrid of the two - a program that has a framerate of 60 seconds, but slowly increases as the game moves along (to emulate the difficulty settings of the original). This helped me to avoid tricky programming, and to keep my rather simplistic movement method in place without a major code rewrite. In order to implement this, I changed the call above to the following:

glutTimerFunc(1000/(60+level*10), myTimer, x);

Now this won't work all the time. The only reason I felt I could get away with it is because I'm doing really simple graphics stuff, and I know that even my laptop's video card can handle it (granted, my card isn't that bad for a mid-powered laptop, but I still have to make occasional allowances).

And that covers the frame rate animation portion. Let's move on to the exciting stuff:

Getting Input from the User

This is where the fun comes from. I'm only going to cover keyboard input here, mouse input will come over the summer, and joystick input will come when I can figure it out (not soon), but for now that's all we need, as we won't necessarily be doing intensive graphics work with slick camera movement schemes. As with everything in Glut, input is obtained through the use of callback functions.

Let's first hit your generic keyboard input (alphanumeric keys, not the function keys). As some of you first person shooter fans will know, the keyboard input can be a much-vaunted alternative to mouse input as it gives you more options at your fingertips (insert random cheesy line about the power of the internet here). The generic function prototype is as follows:

void myKey(unsigned char key, int x, int y);

and is registered as a callback function with the following command:

glutKeyboardFunc(myKey);

As with the vast majority of Glut's callbacks, we can call this function at any point in the program to register a new callback. The prototype gets three pieces of information from glut when a key is pressed: the key pressed (unsigned char key), the x location of the mouse when the key is pressed, and the screen-coordinate y location of the mouse when the key is pressed (relative to the window). Thus, if we have a window that is 320X640, and we position the mouse at the lower right-hand corner of the window and hit "c", key yields a value of 'c', x yields a value of 320, and y yields a value of 640 (note to flip the y value to a more sensible form we just subtract it from the overall window height - in this case, 640-y gives us the standard cartesian Y value of the mouse location). What's coool about the X and Y values is that they work for anywhere on the screen, using the upper left corner of the window as the (0,0) point, and every time you move the game window the origin also moves.

This function is now called every time that a key is pressed by the user. If you're using the keyboard to control program movement, you can stick a switch() statement in here that covers all of the input keys that your program supports (switch is also probably the best way to do it, too, as it ends up just translating into a jump table in the assembly code, which is about as fast as you can get. More on this in future months (maybe, depends on my ambition)). In my program, I've used other keys to implement the movement, but I still use the 'q' key to exit the program, so my "myKey" function looks like this:

void myKey2(unsigned char key, int x, int y){

if( key == 'q'){
delete mine;
exit(0);
}

}

Again, it's as easy as it looks. Just throw in whatever key you want to handle, and make it dance. Woot!

But perhaps you don't want to use letters and numbers to move your program. Maybe you want to be special, and use those quirky arrows and functions keys. It's all good - glut offers a means of using those as well. It's called the glut special func, and it registers the key pressed as an integer, instead of an unsigned character. Thus, the prototype changes to this:

void myKey(int key, int x, int y);

and the callback function is registered with this call:

glutSpecialFunc(myKey);

Every key you press is passed in as an integer value, and the x and y values do the same thing as they did in the keyboard function.

Now, if you're like me, you don't have the integer values of the keys of your keyboard memorized. I mean, how do I know if 27 means "r" or "F12"? No worries, the glut designers anticipated this, and included a series of constants in the header file. You can look them up yourself, but I thought it might be useful to post the list here (along with what the constants map to - aren't I a nice guy?):

  • #define GLUT_KEY_F1 1
  • #define GLUT_KEY_F2 2
  • #define GLUT_KEY_F3 3
  • #define GLUT_KEY_F4 4
  • #define GLUT_KEY_F5 5
  • #define GLUT_KEY_F6 6
  • #define GLUT_KEY_F7 7
  • #define GLUT_KEY_F8 8
  • #define GLUT_KEY_F9 9
  • #define GLUT_KEY_F10 10
  • #define GLUT_KEY_F11 11
  • #define GLUT_KEY_F12 12
  • #define GLUT_KEY_LEFT 100
  • #define GLUT_KEY_UP 101
  • #define GLUT_KEY_RIGHT 102
  • #define GLUT_KEY_DOWN 103
  • #define GLUT_KEY_PAGE_UP 104
  • #define GLUT_KEY_PAGE_DOWN 105
  • #define GLUT_KEY_HOME 106
  • #define GLUT_KEY_END 107
  • #define GLUT_KEY_INSERT 108

This also helps our code to be more readable. Makes it much easier when we do things like work on a program for months at a time - we don't have to remember what button we chose to move the character "left". To demonstrate this, I've included a sample special key function (simplified a bit for the sake of brevity)

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

switch(key){
case GLUT_KEY_LEFT: //GLUT_KEY_LEFT - 100
mine -> moveLeft();
break;
case GLUT_KEY_UP: //GLUT_KEY_UP - 101
mine -> rotPiece(-90);
break;
case GLUT_KEY_RIGHT: //GLUT_KEY_RIGHT - 102
mine -> moveRight();
break;
case GLUT_KEY_DOWN: //GLUT_KEY_DOWN - 103
mine -> moveDown()
break;
};

}

And that's all there is to it. A quick note about this function - it will ONLY work for special keys - this function doesn't register regular letter/number keys (or the escape key). So in order to get full use of your keyboard, you'll need to have both types of functions registered.

hi, thanx for the info..
meabed: am actually workin on TC.what do glutkeys mean.i dont find them in help.will they still work?

hi, thanx for the info..
meabed: am actually workin on TC.what do glutkeys mean.i dont find them in help.will they still work?

Glut and OpenGL

As I said, the initialization code will differ from API to API. I chose to start with Glut, as the initialization code is pretty straightforward (at least, requires a little less brain power to fathom than DirectX). So here it is, our modified
main function:

int main(int argc, char *argv)
{
glutInitWindowPosition(100,100);
glutInitWindowSize(200,200);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("Foobar");
glutDisplayFunc(draw);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glutMainLoop();
return 0;
}

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.