Alex Russell's Game Programming Tutorial using DX

Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7

Chapter 4

Animation

To make an object appear to move it is re-drawn many times a second, but it is moved a little bit each time it is re-drawn. Each drawing is referred to as a `frame'. To get smooth animation you want to draw at least 30 frames per second, and frames rates of 60 or more are ideal. Modern hardware makes it easy to reach these speeds with straight forward techniques. So how do you move an object? You change its x and y coordinates.

Bouncing Pixel

We will make a single pixel bounce in straight lines across the screen next. The pixel will be drawn at the coordinates (x,y) each frame. To make the pixel move right x is increased, to move to the left x is decreased. Increasing y makes the pixel move down and decreasing y makes the pixel move up. Once the pixel reaches the edge of the screen we want it to 'bounce'. Bouncing is done by making the direction we move the pixel the opposite when we reach an edge. If we add dx to x each frame then to bouce all we have to do is make dx the negative of itself.

{
	int done;
	int x, y, dx, dy, width, height, kick;
	DWORD next_time;

	width=dx_p->GetGraphicWidth() - 1;
	height=dx_p->GetGraphicHeight() - 1;
	x=100;  // current x position
	y=200;  // current y position
	done=0; // flag for done
	dx=1;   // amount to move in x direction
	dy=1;   // amount to move in y direction
	next_time=timeGetTime() + 1;  // a timer

	while ( !done )
		{
		// move at a steady speed on all computers
		// if not enough time has NOT passed, redraw the screen without moving
		if ( timeGetTime() >= next_time )
			{
			// move
			x+=dx;
			y+=dy;

			// check for bouncing
			if ( x < 0 )
				{
				x=0;
				dx=-dx;  // move in other direction
				}
			else
				{
				if ( x > width )
					{
					x=width;
					dx=-dx; // move in other direction 
					}
				}

			if ( y < 0 )
				{
				y=0;
				dy=-dy;   // move in other direction 
				}
			else
				{
				if ( y > height )
					{
					y=height;
					dy=-dy;   // move in other direction 
					}
				}

			next_time=timeGetTime();
			}

		// draw, as fast as we can
		dx_p->Pixel(x, y, RGB(0, 255, 0));
		dx_p->Flip();
		}
}


Bouncing Sprite

Drawing a bouncing sprite is exactly the same except you draw a sprite (or bitmap) at (x, y) instead of a single pixel. Only a few minor things change to draw a bitmap compared to the pixel code. We also have to bounce at "screen_width - bitmap_width" (same for height) so that the nitmap stays on the screen.

    gsdxBitmap_t *ball; // bitmap var
    POINT p;

    // load the bitmap, before main loop
    ball=dx_p->LoadBitmap("ball.bmp", NULL);
    if ( !ball )
        return;

    // call Blit() instead of Pixel() in the main loop
    // draw the ball
    p.x=x;
    p.y=y;
    dx_p->Blit(&p, ball);
    dx_p->Flip();

Multiple Bouncing Sprites

To bounce multiple sprites, you just have an array that holds information on the position and direction of each object. Then you loop through the structure and move and draw each object.

// info for one bouncing object
typedef struct
    {
    int x, y;
    int dx, dy;
    }
mini_t;

// multiple bitmaps
void bounce_bitmap2(CgsdxIO *dx_p)
{
	int done;
	int width, height, i, x, y;
	DWORD next_time;
    gsdxBitmap_t *ball;
    gsdxBitmap_t *fullscreen=NULL;
    POINT p;
    mini_t balls[10]; // information on 10 bouncing objects

    ball=dx_p->LoadBitmap("ball.bmp", NULL);
    if ( !ball )
        return;

    width=dx_p->GetGraphicWidth() - 1 - ball->width;
    height=dx_p->GetGraphicHeight() - 1 - ball->height;
    x=10;  // current x position
    y=20;  // current y position
    srand(timeGetTime());
    // set each balls starting position and direction of travel
    for ( i=0; i < 10; i++ )
        {
        balls[i].x=x + (rand()%150);
        balls[i].y=y + (rand()%100);
        balls[i].dx=rand()%2 ? 1 : -1;
        balls[i].dy=rand()%2 ? 1 : -1;
        x+=60;
        y+=50;
        }

	done=0; // flag for done
	next_time=timeGetTime() + 1;  // a timer
	while ( !done )
		{
		// move at a steady speed on all computers
		if ( timeGetTime() >= next_time )
			{
			// move all 10 objects
            		for ( i=0; i < 10; i++ )
                		{
				balls[i].x+=balls[i].dx;
				balls[i].y+=balls[i].dy;

				// check for bouncing
				if ( balls[i].x < 0 )
					{
					balls[i].x=0;
					balls[i].dx=-balls[i].dx;  // move in other direction
					}
				else
					{
					if ( balls[i].x > width )
						{
						balls[i].x=width;
						balls[i].dx=-balls[i].dx; // move in other direction 
						}
				    	}

				if ( balls[i].y < 0 )
					{
					balls[i].y=0;
					balls[i].dy=-balls[i].dy;   // move in other direction 
					}
				else
					{
					if ( balls[i].y > height )
						{
						balls[i].y=height;
						balls[i].dy=-balls[i].dy;   // move in other direction 
						}
					}

	                } // for i

		next_time=timeGetTime() + 1;
		} // if time

	// draw, as fast as we can
        p.x=0;
        p.y=0;
        dx_p->RectFill(NULL, 0); // clear screen

        // draw all 10 balls
        for ( i=0; i < 10; i++ )
            {
            p.x=balls[i].x;
            p.y=balls[i].y;
            dx_p->Blit(&p, ball);
            }

	dx_p->Flip();
	}

    delete ball;

}

Here is the Source code for a demo of a number of simple animations. dx_04.zip requires the next package of source to be added to the class CgsdxIO in the DXSmith library. Insert the source cpp functions into DXSmithIO.cpp, and add the prototypes to public section in the class CgsdxIO in DXSmithIO.h

DXSmith additions

Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7

Copyright 2004 (c), Alex Russell, All rights reserved