Tải bản đầy đủ (.pdf) (74 trang)

Game Programming All in One 2 nd Edition phần 3 pps

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (515.41 KB, 74 trang )

119
Writing Your First
Allegro Game
chapter 4
T
his chapter forges ahead with a lot of things I haven’t discussed yet, such as colli-
sion detection and keyboard input, but the Tank War game that is created in this
chapter will help you absorb all the information presented thus far. You’ll see how
you can use the graphics primitives you learned in Chapter 3 to create a complete game
with support for two players. You will learn how to draw and move a tank around on the
screen using nothing but simple pixel and rectangle drawing functions. You will learn how
to look at the video screen to determine when a projectile strikes a tank or another object,
how to read the keyboard, and how to process a game loop. The goal of this chapter is to
show you that you can create an entire game using the meager resources provided thus far
(in the form of the Allegro functions you have already learned) and to introduce some
new functionality that will be covered in more detail in later chapters.
Here is a breakdown of the major topics in this chapter:

Creating the tanks

Firing weapons

Moving the tanks

Detecting collisions

Understanding the complete source code
Tank War
If this is your first foray into game programming, then Tank War is likely your very first
game! There is always a lot of joy involved in seeing your first game running on the screen.
In the mid-1980s I subscribed to several of the popular computer magazines, such as


Family Computing and Compute!, which provided small program listings in the BASIC
language, most often games. I can still remember some of the games I painstakingly typed
in from the magazine using Microsoft GW-BASIC on my old Tandy 1000. The games
never ran on the first try! I would often miss entire lines of code, even with the benefit of
line numbers in the old style of BASIC.
Today there are fantastic development tools that quite often cost nothing and yet incor-
porate some of the most advanced compiler technology available. The Free Software
Foundation () has done the world a wonderful service by inspiring and
funding the development of free software. Perhaps the most significant contribution by
the FSF is the GNU Compiler Collection, fondly known as GCC. Oddly enough, this very
same compiler is used on both Windows and Linux platforms by the Dev-C++ and
KDevelop tools, respectively. The format of structured and object-oriented code is much
easier to read and follow than in the numbered lines of the past.
Tank War is a two-player game that is played on a single screen using a shared keyboard.
The first player uses the W, A, S, and D keys to move his tank, and the Spacebar to fire the main
cannon on the tank. The second player uses the arrow keys for movement and the Enter
key to fire. The game is shown in Figure 4.1.
Creating the Tanks
The graphics in Tank War are created entirely with the drawing functions included in
Allegro. Figure 4.2 shows the four angles of the tank that are drawn based on the tank’s
direction of travel.
Chapter 4

Writing Your First Allegro Game120
Figure 4.1
Tank War
is a two-player game in the classic style.
The
drawtank
function is called from the main loop to draw each tank according to its

current direction. The
drawtank
function looks like this:
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;
//draw tank body and turret
rectfill(screen, x-11, y-11, x+11, y+11, tanks[num].color);
rectfill(screen, x-6, y-6, x+6, y+6, 7);
//draw the treads based on orientation
if (dir == 0 || dir == 2)
{
rectfill(screen, x-16, y-16, x-11, y+16, 8);
rectfill(screen, x+11, y-16, x+16, y+16, 8);
}
else
if (dir == 1 || dir == 3)
{
rectfill(screen, x-16, y-16, x+16, y-11, 8);
rectfill(screen, x-16, y+16, x+16, y+11, 8);
}
//draw the turret based on direction
switch (dir)
{
case 0:
rectfill(screen, x-1, y, x+1, y-16, 8);
break;
case 1:

rectfill(screen, x, y-1, x+16, y+1, 8);
Tank War 121
Figure 4.2 The tanks are rendered on the screen using a series of filled rectangles.
break;
case 2:
rectfill(screen, x-1, y, x+1, y+16, 8);
break;
case 3:
rectfill(screen, x, y-1, x-16, y+1, 8);
break;
}
}
Did you notice how the entire tank is constructed with
rectfill
statements? This is one
example of improvisation where better technology is not available. For instance, bitmaps
and sprites are not yet available because I haven’t covered that subject yet, so this game
actually draws the tank sprite used in the game. Don’t underestimate the usefulness of
rendered graphics to enhance a sprite-based game or to create a game entirely. To erase
the tank, you simply call the
erasetank
function, which looks like this:
void erasetank(int num)
{
//calculate box to encompass the tank
int left = tanks[num].x - 17;
int top = tanks[num].y - 17;
int right = tanks[num].x + 17;
int bottom = tanks[num].y + 17;
//erase the tank

rectfill(screen, left, top, right, bottom, 0);
}
The
erasetank
function is calculated based on the center of the tank (which is how the tank
is drawn as well, from the center). Because the tank is 32×32 pixels in size, the
erasetank
function draws a black filled rectangle a distance of 17 pixels in each direction from the
center (for a total of 34×34 pixels, to include a small border around the tank, which helps
to keep the tank from getting stuck in obstacles).
Firing Weapons
The projectiles fired from each tank are drawn as small rectangles (four pixels total) that
move in the current direction the tank is facing until they strike the other tank, an object,
or the edge of the screen. You can increase the size of the projectile by increasing the size
in the
updatebullet
function (coming up next). To determine whether a hit has occurred,
you use the
getpixel
function to “look” at the pixel on the screen right in front of the bul-
let. If that pixel is black (color 0 or RGB 0,0,0), then the bullet is moved another space.
Chapter 4

Writing Your First Allegro Game122
If that color is anything other than black, then it is a sure hit! The
fireweapon
function gets
the bullet started in the right direction.
void fireweapon(int num)
{

int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-22;
bullets[num].xspd = 0;
bullets[num].yspd = -BULLETSPEED;
break;
//east
case 1:
bullets[num].x = x+22;
bullets[num].y = y;
bullets[num].xspd = BULLETSPEED;
bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+22;
bullets[num].xspd = 0;
bullets[num].yspd = BULLETSPEED;
break;

//west
case 3:
bullets[num].x = x-22;
bullets[num].y = y;
bullets[num].xspd = -BULLETSPEED;
bullets[num].yspd = 0;
Tank War 123
}
}
}
The
fireweapon
function looks at the direction of the current tank to set the X and Y move-
ment values for the bullet. Once it is set up, the bullet will move in that direction until it
strikes something or reaches the edge of the screen. The important variable here is
alive
,
which determines whether the bullet is moved accordingly using this
updatebullet
function:
void updatebullet(int num)
{
int x = bullets[num].x;
int y = bullets[num].y;
if (bullets[num].alive)
{
//erase bullet
rect(screen, x-1, y-1, x+1, y+1, 0);
//move bullet
bullets[num].x += bullets[num].xspd;

bullets[num].y += bullets[num].yspd;
x = bullets[num].x;
y = bullets[num].y;
//stay within the screen
if (x < 5 || x > SCREEN_W-5 || y < 20 || y > SCREEN_H-5)
{
bullets[num].alive = 0;
return;
}
//draw bullet
x = bullets[num].x;
y = bullets[num].y;
rect(screen, x-1, y-1, x+1, y+1, 14);
//look for a hit
if (getpixel(screen, bullets[num].x, bullets[num].y))
{
bullets[num].alive = 0;
explode(num, x, y);
}
Chapter 4

Writing Your First Allegro Game124
//print the bullet’s position
textprintf(screen, font, SCREEN_W/2-50, 1, 2,
“B1 %-3dx%-3d B2 %-3dx%-3d”,
bullets[0].x, bullets[0].y,
bullets[1].x, bullets[1].y);
}
}
Tank Movement

To move the tank, each player uses the appropriate keys to move forward, backward, left,
right, and to fire the weapon. The first player uses W,A, S, and D to move and the Spacebar
to fire, while player two uses the arrow keys to move and Enter to fire. The main loop
looks for a key press and calls on the
getinput
function to see which key has been pressed.
I will discuss keyboard input in a later chapter; for now all you need to be aware of is an
array called
key
that stores the values of each key press.
void getinput()
{
//hit ESC to quit
if (key[KEY_ESC])
gameover = 1;
//WASD / SPACE keys control tank 1
if (key[KEY_W])
forward(0);
if (key[KEY_D])
turnright(0);
if (key[KEY_A])
turnleft(0);
if (key[KEY_S])
backward(0);
if (key[KEY_SPACE])
fireweapon(0);
//arrow / ENTER keys control tank 2
if (key[KEY_UP])
forward(1);
if (key[KEY_RIGHT])

turnright(1);
if (key[KEY_DOWN])
backward(1);
if (key[KEY_LEFT])
Tank War 125
turnleft(1);
if (key[KEY_ENTER])
fireweapon(1);
//short delay after keypress
rest(10);
}
Collision Detection
I have already explained how the bullets use
getpixel
to determine when a collision has
occurred (when the bullet hits a tank or obstacle). But what about collision detection when
you are moving the tanks themselves? There are several obstacles on the battlefield to add
a little strategy to the game; they offer a place to hide or maneuver around (or straight
through if you blow up the obstacles). The
clearpath
function is used to determine whether
the ship can move. The function checks the screen boundaries and obstacles on the screen
to clear a path for the tank or prevent it from moving any further in that direction. The
function also takes into account reverse motion because the tanks can move forward or
backward.
clearpath
is a bit lengthy, so I’ll leave it for the main code listing later in the chap-
ter. The
clearpath
function calls the

checkpath
function to actually see whether the tank’s
pathway is clear for movement. (
checkpath
is called multiple times for each tank.)
int checkpath(int x1,int y1,int x2,int y2,int x3,int y3)
{
if (getpixel(screen, x1, y1) ||
getpixel(screen, x2, y2) ||
getpixel(screen, x3, y3))
return 1;
else
return 0;
}
All that remains of the program are the logistical functions for setting up the screen, mod-
ifying the speed and direction of each tank, displaying the score, placing the random
debris, and so on.
The Complete Tank War Source Code
The code listing for Tank War is included here in its entirety. Despite having already
shown you many of the functions in this program, I think it’s important at this point to
show you the entire listing in one fell swoop so there is no confusion. Of course, you can
open the Tank War project that is located on the CD-ROM that accompanies this book;
look inside a folder called chapter04 for the complete project for Visual C++, Dev-C++,
or KDevelop. If you are using some other operating system, you can still compile this code
Chapter 4

Writing Your First Allegro Game126
for your favorite compiler by typing it into your text editor and including the Allegro
library. (If you need some pointers, refer to Appendix E,“Configuring Allegro for Microsoft
Visual C++ and Other Compilers.”)

The Tank War Header File
The first code listing is for the header file, which includes the variables, structures, con-
stants, and function prototypes for the game. You will want to add a new file to the pro-
ject called tankwar.h. The main source code file (main.c) will try to include the header file
by this filename. If you need help configuring your compiler to link to the Allegro game
library, refer to Appendix E. If you have not yet installed Allegro, you might want to go
back and read Chapter 2 and refer to Appendix F, “Compiling the Allegro Source Code.”
/////////////////////////////////////////////////////////////////////////
// Game Programming All In One, Second Edition
// Source Code Copyright (C)2004 by Jonathan S. Harbour
// Chapter 4 - Tank War Game
/////////////////////////////////////////////////////////////////////////
#ifndef _TANKWAR_H
#define _TANKWAR_H
#include “allegro.h”
//define some game constants
#define MODE GFX_AUTODETECT_WINDOWED
#define WIDTH 640
#define HEIGHT 480
#define BLOCKS 5
#define BLOCKSIZE 100
#define MAXSPEED 2
#define BULLETSPEED 10
#define TAN makecol(255,242,169)
#define CAMO makecol(64,142,66)
#define BURST makecol(255,189,73)
//define tank structure
struct tagTank
{
int x,y;

int dir,speed;
int color;
int score;
Tank War 127
} tanks[2];
//define bullet structure
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];
int gameover = 0;
//function prototypes
void drawtank(int num);
void erasetank(int num);
void movetank(int num);
void explode(int num, int x, int y);
void updatebullet(int num);
int checkpath(int x1,int y1,int x2,int y2,int x3,int y3);
void clearpath(int num);
void fireweapon(int num);
void forward(int num);
void backward(int num);
void turnleft(int num);
void turnright(int num);
void getinput();
void setuptanks();
void score(int);
void print(const char *s, int c);

void setupdebris();
void setupscreen();
#endif
The Tank War Source File
The primary source code file for Tank War includes the tankwar.h header file (which in
turn includes allegro.h). Included in this code listing are all of the functions needed by the
game in addition to the
main
function (containing the game loop). You can type this code
in as-is for whatever OS and IDE you are using; if you have included the Allegro library,
it will run without issue. This game is wonderfully easy to get to work because it requires
no bitmap files, uses no backgrounds, and simply draws directly to the primary screen
buffer (which can be full-screen or windowed).
Chapter 4

Writing Your First Allegro Game128
/////////////////////////////////////////////////////////////////////////
// Game Programming All In One, Second Edition
// Source Code Copyright (C)2004 by Jonathan S. Harbour
// Chapter 4 - Tank War Game
/////////////////////////////////////////////////////////////////////////
#include “tankwar.h”
/////////////////////////////////////////////////////////////////////////
// drawtank function
// construct the tank using drawing functions
/////////////////////////////////////////////////////////////////////////
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;

int dir = tanks[num].dir;
//draw tank body and turret
rectfill(screen, x-11, y-11, x+11, y+11, tanks[num].color);
rectfill(screen, x-6, y-6, x+6, y+6, 7);
//draw the treads based on orientation
if (dir == 0 || dir == 2)
{
rectfill(screen, x-16, y-16, x-11, y+16, 8);
rectfill(screen, x+11, y-16, x+16, y+16, 8);
}
else
if (dir == 1 || dir == 3)
{
rectfill(screen, x-16, y-16, x+16, y-11, 8);
rectfill(screen, x-16, y+16, x+16, y+11, 8);
}
//draw the turret based on direction
switch (dir)
{
case 0:
rectfill(screen, x-1, y, x+1, y-16, 8);
break;
case 1:
rectfill(screen, x, y-1, x+16, y+1, 8);
Tank War 129
break;
case 2:
rectfill(screen, x-1, y, x+1, y+16, 8);
break;
case 3:

rectfill(screen, x, y-1, x-16, y+1, 8);
break;
}
}
/////////////////////////////////////////////////////////////////////////
// erasetank function
// erase the tank using rectfill
/////////////////////////////////////////////////////////////////////////
void erasetank(int num)
{
//calculate box to encompass the tank
int left = tanks[num].x - 17;
int top = tanks[num].y - 17;
int right = tanks[num].x + 17;
int bottom = tanks[num].y + 17;
//erase the tank
rectfill(screen, left, top, right, bottom, 0);
}
/////////////////////////////////////////////////////////////////////////
// movetank function
// move the tank in the current direction
/////////////////////////////////////////////////////////////////////////
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;
//update tank position based on direction
switch(dir)
{
case 0:

tanks[num].y -= speed;
break;
case 1:
tanks[num].x += speed;
Chapter 4

Writing Your First Allegro Game130
break;
case 2:
tanks[num].y += speed;
break;
case 3:
tanks[num].x -= speed;
}
//keep tank inside the screen
if (tanks[num].x > SCREEN_W-22)
{
tanks[num].x = SCREEN_W-22;
tanks[num].speed = 0;
}
if (tanks[num].x < 22)
{
tanks[num].x = 22;
tanks[num].speed = 0;
}
if (tanks[num].y > SCREEN_H-22)
{
tanks[num].y = SCREEN_H-22;
tanks[num].speed = 0;
}

if (tanks[num].y < 22)
{
tanks[num].y = 22;
tanks[num].speed = 0;
}
}
/////////////////////////////////////////////////////////////////////////
// explode function
// display random boxes to simulate an explosion
/////////////////////////////////////////////////////////////////////////
void explode(int num, int x, int y)
{
int n;
//retrieve location of enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;
Tank War 131
//is bullet inside the boundary of the enemy tank?
if (x > tx-16 && x < tx+16 && y > ty-16 && y < ty+16)
score(num);
//draw some random circles for the “explosion”
for (n = 0; n < 10; n++)
{
rectfill(screen, x-16, y-16, x+16, y+16, rand() % 16);
rest(1);
}
//clear the area of debris
rectfill(screen, x-16, y-16, x+16, y+16, 0);
}
/////////////////////////////////////////////////////////////////////////

// updatebullet function
// update the position of a bullet
/////////////////////////////////////////////////////////////////////////
void updatebullet(int num)
{
int x = bullets[num].x;
int y = bullets[num].y;
if (bullets[num].alive)
{
//erase bullet
rect(screen, x-1, y-1, x+1, y+1, 0);
//move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
x = bullets[num].x;
y = bullets[num].y;
//stay within the screen
if (x < 5 || x > SCREEN_W-5 || y < 20 || y > SCREEN_H-5)
{
bullets[num].alive = 0;
return;
}
Chapter 4

Writing Your First Allegro Game132
//draw bullet
x = bullets[num].x;
y = bullets[num].y;
rect(screen, x-1, y-1, x+1, y+1, 14);
//look for a hit

if (getpixel(screen, bullets[num].x, bullets[num].y))
{
bullets[num].alive = 0;
explode(num, x, y);
}
//print the bullet’s position
textprintf(screen, font, SCREEN_W/2-50, 1, 2,
“B1 %-3dx%-3d B2 %-3dx%-3d”,
bullets[0].x, bullets[0].y,
bullets[1].x, bullets[1].y);
}
}
/////////////////////////////////////////////////////////////////////////
// checkpath function
// check to see if a point on the screen is black
/////////////////////////////////////////////////////////////////////////
int checkpath(int x1,int y1,int x2,int y2,int x3,int y3)
{
if (getpixel(screen, x1, y1) ||
getpixel(screen, x2, y2) ||
getpixel(screen, x3, y3))
return 1;
else
return 0;
}
/////////////////////////////////////////////////////////////////////////
// clearpath function
// verify that the tank can move in the current direction
/////////////////////////////////////////////////////////////////////////
void clearpath(int num)

{
//shortcut vars
int dir = tanks[num].dir;
Tank War 133
int speed = tanks[num].speed;
int x = tanks[num].x;
int y = tanks[num].y;
switch(dir)
{
//check pixels north
case 0:
if (speed > 0)
{
if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
tanks[num].speed = 0;
}
else
//if reverse dir, check south
if (checkpath(x-16, y+20, x, y+20, x+16, y+20))
tanks[num].speed = 0;
break;
//check pixels east
case 1:
if (speed > 0)
{
if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
tanks[num].speed = 0;
}
else
//if reverse dir, check west

if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
tanks[num].speed = 0;
break;
//check pixels south
case 2:
if (speed > 0)
{
if (checkpath(x-16, y+20, x, y+20, x+16, y+20 ))
tanks[num].speed = 0;
}
else
//if reverse dir, check north
if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
tanks[num].speed = 0;
Chapter 4

Writing Your First Allegro Game134
break;
//check pixels west
case 3:
if (speed > 0)
{
if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
tanks[num].speed = 0;
}
else
//if reverse dir, check east
if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
tanks[num].speed = 0;
break;

}
}
/////////////////////////////////////////////////////////////////////////
// fireweapon function
// configure a bullet’s direction and speed and activate it
/////////////////////////////////////////////////////////////////////////
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-22;
bullets[num].xspd = 0;
bullets[num].yspd = -BULLETSPEED;
break;
//east
case 1:
Tank War 135
bullets[num].x = x+22;
bullets[num].y = y;
bullets[num].xspd = BULLETSPEED;

bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+22;
bullets[num].xspd = 0;
bullets[num].yspd = BULLETSPEED;
break;
//west
case 3:
bullets[num].x = x-22;
bullets[num].y = y;
bullets[num].xspd = -BULLETSPEED;
bullets[num].yspd = 0;
}
}
}
/////////////////////////////////////////////////////////////////////////
// forward function
// increase the tank’s speed
/////////////////////////////////////////////////////////////////////////
void forward(int num)
{
tanks[num].speed++;
if (tanks[num].speed > MAXSPEED)
tanks[num].speed = MAXSPEED;
}
/////////////////////////////////////////////////////////////////////////
// backward function

// decrease the tank’s speed
/////////////////////////////////////////////////////////////////////////
void backward(int num)
{
tanks[num].speed—;
if (tanks[num].speed < -MAXSPEED)
tanks[num].speed = -MAXSPEED;
}
Chapter 4

Writing Your First Allegro Game136
/////////////////////////////////////////////////////////////////////////
// turnleft function
// rotate the tank counter-clockwise
/////////////////////////////////////////////////////////////////////////
void turnleft(int num)
{
tanks[num].dir—;
if (tanks[num].dir < 0)
tanks[num].dir = 3;
}
/////////////////////////////////////////////////////////////////////////
// turnright function
// rotate the tank clockwise
/////////////////////////////////////////////////////////////////////////
void turnright(int num)
{
tanks[num].dir++;
if (tanks[num].dir > 3)
tanks[num].dir = 0;

}
/////////////////////////////////////////////////////////////////////////
// getinput function
// check for player input keys (2 player support)
/////////////////////////////////////////////////////////////////////////
void getinput()
{
//hit ESC to quit
if (key[KEY_ESC])
gameover = 1;
//WASD / SPACE keys control tank 1
if (key[KEY_W])
forward(0);
if (key[KEY_D])
turnright(0);
if (key[KEY_A])
turnleft(0);
if (key[KEY_S])
backward(0);
if (key[KEY_SPACE])
fireweapon(0);
Tank War 137
//arrow / ENTER keys control tank 2
if (key[KEY_UP])
forward(1);
if (key[KEY_RIGHT])
turnright(1);
if (key[KEY_DOWN])
backward(1);
if (key[KEY_LEFT])

turnleft(1);
if (key[KEY_ENTER])
fireweapon(1);
//short delay after keypress
rest(10);
}
/////////////////////////////////////////////////////////////////////////
// score function
// add a point to the specified player’s score
/////////////////////////////////////////////////////////////////////////
void score(int player)
{
//update score
int points = ++tanks[player].score;
//display score
textprintf(screen, font, SCREEN_W-70*(player+1), 1, BURST,
“P%d: %d”, player+1, points);
}
/////////////////////////////////////////////////////////////////////////
// setuptanks function
// set up the starting condition of each tank
/////////////////////////////////////////////////////////////////////////
void setuptanks()
{
//player 1
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 0;
tanks[0].color = 9;

tanks[0].score = 0;
Chapter 4

Writing Your First Allegro Game138
//player 2
tanks[1].x = SCREEN_W-30;
tanks[1].y = SCREEN_H-30;
tanks[1].dir = 3;
tanks[1].speed = 0;
tanks[1].color = 12;
tanks[1].score = 0;
}
/////////////////////////////////////////////////////////////////////////
// setupdebris function
// set up the debris on the battlefield
/////////////////////////////////////////////////////////////////////////
void setupdebris()
{
int n,x,y,size,color;
//fill the battlefield with random debris
for (n = 0; n < BLOCKS; n++)
{
x = BLOCKSIZE + rand() % (SCREEN_W-BLOCKSIZE*2);
y = BLOCKSIZE + rand() % (SCREEN_H-BLOCKSIZE*2);
size = (10 + rand() % BLOCKSIZE)/2;
color = makecol(rand()%255, rand()%255, rand()%255);
rectfill(screen, x-size, y-size, x+size, y+size, color);
}
}
/////////////////////////////////////////////////////////////////////////

// setupscreen function
// set up the graphics mode and game screen
/////////////////////////////////////////////////////////////////////////
void setupscreen()
{
//set video mode
int ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);
if (ret != 0) {
allegro_message(allegro_error);
return;
}
Tank War 139
//print title
textprintf(screen, font, 1, 1, BURST,
“Tank War - %dx%d”, SCREEN_W, SCREEN_H);
//draw screen border
rect(screen, 0, 12, SCREEN_W-1, SCREEN_H-1, TAN);
rect(screen, 1, 13, SCREEN_W-2, SCREEN_H-2, TAN);
}
/////////////////////////////////////////////////////////////////////////
// main function
// start point of the program
/////////////////////////////////////////////////////////////////////////
void main(void)
{
//initialize everything
allegro_init();
install_keyboard();
install_timer();
srand(time(NULL));

setupscreen();
setupdebris();
setuptanks();
//game loop
while(!gameover)
{
//erase the tanks
erasetank(0);
erasetank(1);
//check for collisions
clearpath(0);
clearpath(1);
//move the tanks
movetank(0);
movetank(1);
//draw the tanks
drawtank(0);
drawtank(1);
Chapter 4

Writing Your First Allegro Game140
//update the bullets
updatebullet(0);
updatebullet(1);
//check for keypresses
if (keypressed())
getinput();
//slow the game down (adjust as necessary)
rest(30);
}

//end program
allegro_exit();
}
END_OF_MAIN();
Summary
Congratulations on completing your first game with Allegro! It has been a short journey
thus far—we’re only in the fourth chapter of the book. Contrast this with the enormous
amount of information that would have been required in advance to compile even a simple
game, such as Tank War, using standard graphics libraries, such as DirectX or SVGAlib!
It would have taken this amount of source code just to set up the screen and prepare the
program for the actual game. That is where Allegro truly shines—by abstracting the logis-
tical issues into a common set of library functions that work regardless of the underlying
operating system.
This also concludes Part I of the book and sends you venturing into Part II, which covers
the core functionality of Allegro in much more detail. You will learn how to use animated
sprites and create scrolling backgrounds, and we’ll discuss the next upgrade to Tank War.
That’s right, this isn’t the end of Tank War! From this point forward, we’ll be improving
the game with each new chapter. For starters, this game really needs some design and
direction (the focus of Chapter 5). By the time you’re finished, the game will feature a
scrolling background, a tile-based battlefield, sound effects…the whole works!
Tank War 141
Chapter Quiz
You can find the answers to this chapter quiz in Appendix A, “Chapter Quiz Answers.”
1. What is the primary graphics drawing function used to draw the tanks in Tank War?
A.
rectfill
B.
fillrect
C.
drawrect

D.
rectangle
2. What function in Tank War sets up a bullet to fire it in the direction of the tank?
A.
pulltrigger
B.
launchprojectile
C.
fireweapon
D.
firecannon
3. What function in Tank War updates the position and draws each projectile?
A.
updatecannon
B.
movebullet
C.
moveprojectile
D.
updatebullet
4. What is the name of the organization that produced GCC?
A. Free Software Foundation
B. GNU
C. Freeware
D. Open Source
5. How many players are supported in Tank War at the same time?
A. 1
B. 2
C. 3
D. 4

6. What is the technical terminology for handling two objects that crash in the game?
A. Crash override
B. Sprite insurance
C. Collision detection
D. Handling the crash
Chapter 4

Writing Your First Allegro Game142
7. What function in Tank War keeps the tanks from colliding with other objects?
A.
makepath
B.
clearpath
C.
buildpath
D.
dontcollide
8. Which function in Tank War helps to find out whether a point on the screen is
black?
A.
getpixel
B.
findcolor
C.
getcolor
D.
checkpixel
9. What is the standard constant used to run Allegro in windowed mode?
A.
GFX_RUNINA_WINDOW

B.
GFX_DETECT_WINDOWED
C.
GFX_AUTODETECT_WINDOWS
D.
GFX_AUTODETECT_WINDOWED
10. What function in Allegro is used to slow the game down?
A.
pause
B.
slow
C.
rest
D.
stop
Chapter Quiz 143

×