Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 74 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
74
Dung lượng
518,05 KB
Nội dung
explode_bmp = load_bitmap(“explode.bmp”, NULL); } //draw the explosion bitmap several times for (n = 0; n < 5; n++) { rotate_sprite(screen, explode_bmp, x + rand()%10 - 20, y + rand()%10 - 20, itofix(rand()%255)); rest(30); } //clear the explosion circlefill(screen, x, y, 50, BLACK); } ///////////////////////////////////////////////////////////////////// // updatebullet function // update the position of a bullet ///////////////////////////////////////////////////////////////////// void updatebullet(int num) { int x = bullets[num].x; int y = bullets[num].y; //is the bullet active? if (!bullets[num].alive) return; //erase bullet rectfill(screen, x, y, x+10, y+10, BLACK); //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 < 6 || x > SCREEN_W-6 || y < 20 || y > SCREEN_H-6) { bullets[num].alive = 0; Enhancing Tank War 267 return; } //look for a direct hit using basic collision //tank is either 0 or 1, so negative num = other tank int tx = tanks[!num].x; int ty = tanks[!num].y; if (x > tx-16 && x < tx+16 && y > ty-16 && y < ty+16) { //kill the bullet bullets[num].alive = 0; //blow up the tank explode(num, x, y); score(num); } else //if no hit then draw the bullet { //draw bullet sprite draw_sprite(screen, bullet_bmp, x, y); //update the bullet positions (for debugging) textprintf(screen, font, SCREEN_W/2-50, 1, TAN, “B1 %-3dx%-3d B2 %-3dx%-3d”, bullets[0].x, bullets[0].y, bullets[1].x, bullets[1].y); } } ///////////////////////////////////////////////////////////////////// // fireweapon function // set bullet direction and speed and activate it ///////////////////////////////////////////////////////////////////// void fireweapon(int num) { int x = tanks[num].x; int y = tanks[num].y; //load bullet image if necessary if (bullet_bmp == NULL) { Chapter 8 ■ Basic Sprite Programming268 bullet_bmp = load_bitmap(“bullet.bmp”, NULL); } //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-2; bullets[num].y = y-22; bullets[num].xspd = 0; bullets[num].yspd = -BULLETSPEED; break; //NE case 1: bullets[num].x = x+18; bullets[num].y = y-18; bullets[num].xspd = BULLETSPEED; bullets[num].yspd = -BULLETSPEED; break; //east case 2: bullets[num].x = x+22; bullets[num].y = y-2; bullets[num].xspd = BULLETSPEED; bullets[num].yspd = 0; break; //SE case 3: bullets[num].x = x+18; bullets[num].y = y+18; bullets[num].xspd = BULLETSPEED; bullets[num].yspd = BULLETSPEED; break; //south case 4: bullets[num].x = x-2; bullets[num].y = y+22; Enhancing Tank War 269 bullets[num].xspd = 0; bullets[num].yspd = BULLETSPEED; break; //SW case 5: bullets[num].x = x-18; bullets[num].y = y+18; bullets[num].xspd = -BULLETSPEED; bullets[num].yspd = BULLETSPEED; break; //west case 6: bullets[num].x = x-22; bullets[num].y = y-2; bullets[num].xspd = -BULLETSPEED; bullets[num].yspd = 0; break; //NW case 7: bullets[num].x = x-18; bullets[num].y = y-18; bullets[num].xspd = -BULLETSPEED; bullets[num].yspd = -BULLETSPEED; break; } } } The next section of code covers the keyboard input code, including forward , backward , turnleft , turnright , and getinput . These functions are largely the same as before, but they now must support eight directions (evident in the if statement within turnleft and turnright ). ///////////////////////////////////////////////////////////////////// // forward function // increase the tank’s speed ///////////////////////////////////////////////////////////////////// void forward(int num) { tanks[num].speed++; if (tanks[num].speed > MAXSPEED) tanks[num].speed = MAXSPEED; } Chapter 8 ■ Basic Sprite Programming270 ///////////////////////////////////////////////////////////////////// // backward function // decrease the tank’s speed ///////////////////////////////////////////////////////////////////// void backward(int num) { tanks[num].speed—; if (tanks[num].speed < -MAXSPEED) tanks[num].speed = -MAXSPEED; } ///////////////////////////////////////////////////////////////////// // turnleft function // rotate the tank counter-clockwise ///////////////////////////////////////////////////////////////////// void turnleft(int num) { //*** tanks[num].dir—; if (tanks[num].dir < 0) tanks[num].dir = 7; } ///////////////////////////////////////////////////////////////////// // turnright function // rotate the tank clockwise ///////////////////////////////////////////////////////////////////// void turnright(int num) { tanks[num].dir++; if (tanks[num].dir > 7) 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; Enhancing Tank War 271 //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]) turnleft(1); if (key[KEY_ENTER]) fireweapon(1); //short delay after keypress rest(20); } The next short code section includes the score function that is used to update the score for each player. ///////////////////////////////////////////////////////////////////// // score function // add a point to a 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); } The setuptanks function has changed dramatically from the last version because that is where the new tank bitmaps are loaded. Since this game uses the rotate_sprite function to generate the sprite images for all eight directions, this function takes care of that by first creating each image and then blitting the source tank image into each new image with a specified rotation angle. The end result is two tanks fully rotated in eight directions. ///////////////////////////////////////////////////////////////////// // setuptanks function // load tank bitmaps and position the tank ///////////////////////////////////////////////////////////////////// Chapter 8 ■ Basic Sprite Programming272 void setuptanks() { int n; //configure player 1’s tank tanks[0].x = 30; tanks[0].y = 40; tanks[0].speed = 0; tanks[0].score = 0; tanks[0].dir = 3; //load first tank bitmap tank_bmp[0][0] = load_bitmap(“tank1.bmp”, NULL); //rotate image to generate all 8 directions for (n=1; n<8; n++) { tank_bmp[0][n] = create_bitmap(32, 32); clear_bitmap(tank_bmp[0][n]); rotate_sprite(tank_bmp[0][n], tank_bmp[0][0], 0, 0, itofix(n*32)); } //configure player 2’s tank tanks[1].x = SCREEN_W-30; tanks[1].y = SCREEN_H-30; tanks[1].speed = 0; tanks[1].score = 0; tanks[1].dir = 7; //load second tank bitmap tank_bmp[1][0] = load_bitmap(“tank2.bmp”, NULL); //rotate image to generate all 8 directions for (n=1; n<8; n++) { tank_bmp[1][n] = create_bitmap(32, 32); clear_bitmap(tank_bmp[1][n]); rotate_sprite(tank_bmp[1][n], tank_bmp[1][0], 0, 0, itofix(n*32)); } } Enhancing Tank War 273 The next section of the code includes the setupscreen function. The most important change to this function is the inclusion of a single line calling set_color_depth(32) , which causes the game to run in 32-bit color mode. Note that if you don’t have a 32-bit video card, you might want to change this to 16 (which will still work). ///////////////////////////////////////////////////////////////////// // setupscreen function // set up the graphics mode and draw the game screen ///////////////////////////////////////////////////////////////////// void setupscreen() { //set video mode set_color_depth(32); int ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0); if (ret != 0) { allegro_message(allegro_error); return; } //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); } Finally, the last section of code in the third enhancement to Tank War includes the all- important main function. Several changes have been made in main , notably the removal of the calls to clearpath (which checked for bullet hits by looking directly at pixel color). The call to rest now has a value of 10 to speed up the game a bit in order to have smoother bullet trajectories. There is also a line of code that displays the direction of each tank, as I explained previously. ///////////////////////////////////////////////////////////////////// // main function // start point of the program ///////////////////////////////////////////////////////////////////// void main(void) { //initialize the game Chapter 8 ■ Basic Sprite Programming274 allegro_init(); install_keyboard(); install_timer(); srand(time(NULL)); setupscreen(); setuptanks(); //game loop while(!gameover) { textprintf(screen, font, 0, SCREEN_H-10, WHITE, “DIRS %d , %d”, tanks[0].dir, tanks[1].dir); //erase the tanks erasetank(0); erasetank(1); //move the tanks movetank(0); movetank(1); //draw the tanks drawtank(0); drawtank(1); //update the bullets updatebullet(0); updatebullet(1); //check for keypresses if (keypressed()) getinput(); //slow the game down rest(10); } //end program allegro_exit(); } END_OF_MAIN(); Enhancing Tank War 275 Summary This marks the end of perhaps the most interesting chapter so far, at least in my opinion. The introduction to sprites that you have received in this chapter provided the basics without delving too deeply into sprite programming theory. The next chapter covers some advanced sprite programming topics, including the sorely needed collision detection. I will also get into sprite animation in the next chapter. There are many more changes on the way for Tank War as well. The next several chapters will provide a huge amount of new functionality that you can use to greatly enhance Tank War, making it into a truly top- notch game with a scrolling background, animated tanks, a radar screen, and many more new features! Chapter Quiz You can find the answers to this chapter quiz in Appendix A, “Chapter Quiz Answers.” 1. What is the term given to a small image that is moved around on the screen? A. Bitmap B. Sprite C. Fairy D. Mouse cursor 2. Which function draws a sprite? A. draw_sprite B. show_sprite C. display_sprite D. blit_sprite 3. What is the term for drawing all but a certain color of pixel from one bitmap to another? A. Alpha blending B. Translucency C. Transparency D. Telekinesis 4. Which function draws a scaled sprite? A. stretch_sprite B. draw_scaled_sprite C. draw_stretched_sprite D. scale_sprite Chapter 8 ■ Basic Sprite Programming276 [...]... Figure 9 .2 The AnimSprite program shows how you can do basic sprite animation #include #include #include #include “allegro.h” #define WHITE makecol ( 25 5 , 25 5 , 25 5) #define BLACK makecol(0,0,0) BITMAP *kitty[7]; char s [20 ]; int curframe=0, framedelay =5, framecount=0; int x=100, y =20 0, n; int main(void) { //initialize the program allegro_init(); install_keyboard(); install_timer();... ballimg[n] = load_bitmap(s, NULL); } //initialize the sprite with lots of randomness ball->x = rand() % (SCREEN_W - ballimg[0]->w); ball->y = rand() % (SCREEN_H - ballimg[0]->h); ball->width = ballimg[0]->w; ball->height = ballimg[0]->h; ball->xdelay = rand() % 2 + 1; ball->ydelay = rand() % 2 + 1; ball->xcount = 0; ball->ycount = 0; ball->xspeed = rand() % 2 + 4; ball->yspeed = rand() % 2 + 4; ball->curframe... “allegro.h” #define BLACK makecol(0,0,0) #define WHITE makecol ( 25 5 , 25 5 , 25 5) 29 3 29 4 Chapter 9 I Advanced Sprite Programming //define the sprite structure typedef struct SPRITE { int x,y; int width,height; int xspeed,yspeed; int xdelay,ydelay; int xcount,ycount; int curframe,maxframe,animdir; int framecount,framedelay; }SPRITE; //sprite variables BITMAP *ballimg[ 32] ; SPRITE theball; SPRITE *ball... (SCREEN_W - ballimg[0]->w); ball->y = rand() % (SCREEN_H - ballimg[0]->h); ball->width = ballimg[0]->w; ball->height = ballimg[0]->h; ball->xdelay = rand() % 2 + 1; ball->ydelay = rand() % 2 + 1; ball->xcount = 0; ball->ycount = 0; ball->xspeed = rand() % 2 + 4; ball->yspeed = rand() % 2 + 4; ball->curframe = 0; ball->maxframe = 31; ball->framecount = 0; ball->framedelay = 1; ball->animdir = 1; / /game loop... strategy game Following is the complete listing for the MultipleSprites program If you are typing in the code directly from the book, you will want to grab the asteroids.bmp and ngc604.bmp files from the CD-ROM (They are located in \chapter09\multiplesprites.) #include #include #include #include “allegro.h” #define BLACK makecol(0,0,0) #define WHITE makecol ( 25 5 , 25 5 , 25 5) #define... bitmap image and grab the frames out of it at run time I’ll show you how to do that shortly Figure 9.4 shows the SpriteHandler program running Each time the ball hits the edge, it changes direction and speed #include #include #include #include “allegro.h” #define BLACK makecol(0,0,0) #define WHITE makecol ( 25 5 , 25 5 , 25 5) Animated Sprites Figure 9.4 The SpriteHandler program... draw_sprite(screen, ballimg[ball->curframe], ball->x, ball->y); //display some logistics textprintf(screen, font, 0, 20 , WHITE, “x,y,xspeed,yspeed: %2d,%2d,%2d,%2d”, Animated Sprites ball->x, ball->y, ball->xspeed, ball->yspeed); textprintf(screen, font, 0, 30, WHITE, “xcount,ycount,framecount,animdir: %2d,%2d,%2d,%2d”, ball->xcount, ball->ycount, ball->framecount, ball->animdir); //unlock the screen release_screen();... rand() % 2 - 6; spr->animdir *= -1; } } void main(void) { //initialize allegro_init(); set_color_depth(16); set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); install_keyboard(); install_timer(); srand(time(NULL)); textout(screen, font, “SpriteHandler Program (ESC to quit)”, 0, 0, WHITE); 28 9 29 0 Chapter 9 I Advanced Sprite Programming //load sprite images for (n=0; ncurframe], ball->x, ball->y); //display some logistics textprintf(screen, font, 0, 20 , WHITE, “x,y,xspeed,yspeed: %2d,%2d,%2d,%2d”, ball->x, ball->y, ball->xspeed,... animated sprite handler //define the sprite structure typedef struct SPRITE { int x,y; int width,height; int xspeed,yspeed; int xdelay,ydelay; int xcount,ycount; int curframe,maxframe,animdir; int framecount,framedelay; }SPRITE; //sprite variables BITMAP *ballimg[16]; SPRITE theball; SPRITE *ball = &theball; //support variables char s [20 ]; int n; 28 7 28 8 Chapter 9 I Advanced Sprite Programming void erasesprite(BITMAP . Feldman #include <conio.h> #include <stdlib.h> #include <stdio.h> #include “allegro.h” #define WHITE makecol ( 25 5 , 25 5 , 25 5) #define BLACK makecol(0,0,0) BITMAP *kitty[7]; char s [20 ]; int. direction and speed. #include <conio.h> #include <stdlib.h> #include <stdio.h> #include “allegro.h” #define BLACK makecol(0,0,0) #define WHITE makecol ( 25 5 , 25 5 , 25 5) Chapter 9. framedelay =5, framecount=0; int x=100, y =20 0, n; int main(void) { //initialize the program allegro_init(); install_keyboard(); install_timer(); set_color_depth(16); set_gfx_mode(GFX_AUTODETECT_WINDOWED,