EVIL STICK MAN ENTERPRISES

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

by Matt Billock

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. How do I get there, you ask? Simple! Just point your browser at
http://www.evilstickman.com and check out the TechTrax section. 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 0.

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(unsignedchar 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(unsignedchar 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.

 Your First Game

 With that said, you now have in your power everything you need to make  a game. Don't believe me? Well, I've created a game using just the knowledge presented thus far, just to prove that point (ain't I sneaky :-P). Also,  think about it - we've covered drawing, processing user input, and receiving  user input - back in the second article I wrote I said that that was essentially all a game did - those three things (yeah,  I know, I said "Update" instead of "Process input", but they are essentially the same thing, and are both implemented through the timer function anyway). So to celebrate, I've created my very own tetris clone. Of course, due to copyright issues, we can't call it tetris, so I've named it "Super Falling Blocks of DOOM!" (not related to any products by ID Software). Either that or "The Effervescent Tumbling Rock Images, Seriously!"  (T.E.T.R.I.S.),  though the individual pieces aren't very effervescent (I didn't program in any  bubbles, at least).

Now the game isn't perfect, by any means, and it isn't very pretty, but it is  fully functional. It rotates pieces, moves them around, has them speed up as you complete more lines, and in general does everything a good tetris game should.  I've uploaded the source code (commented) and VS.NET 2003 project files to
http://www.evilstickman.com/zips/tetris.zip,  so that you may download and browse through it at your leisure (caution - it's about a 3 meg dowload).

Some quick notes about the game, largely due to my non 1337 programming skills.  The pieces don't rotate around a true center, they spin about a piece in the tetrad. Also, if you hold down while a piece is being generated, it actually appears a space or three further down the screen (so be careful!). Also, the  repeat rate is limited to that set by your OS, so in order to keep moving the piece you either have to hold onto the button or press it a bunch of times. And make sure you have glut.dll either in your system directory or in the program directory, or it won't run.

Controls are "up" to rotate the piece, "left" to move left one square, "right" to move right one square, "down" to move down one square, and "q" to quit the game.

And that does it for this month. Don't forget that Techtrax goes on vacation for a couple months, and you'll have to find your fresh game programming action  at
http://www.evilstickman.com. Also,  feel free to e-mail me anything you build using knowledge gained thus far, and I'll post either a link or screenshots on my website. And don't hesitate to contact  me directly with comments or questions regarding the article or any of my code. Until September!

Copyright (c) 2004 by Matthew Raymond Billock. All images and content on this website are original creations by Matthew Raymond Billock. Use of logos, images, or the Evil Stick Man Enterprises name without express written permission is prohibited