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

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

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

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 (http://www.fsf.org) 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 [...]... 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 1 43 This page intentionally left blank chapter 5 Programming the Keyboard, Mouse, and Joystick elcome to the input chapter, focusing on programming the keyboard, mouse, and joystick!... topics in this chapter: I I I I I I I Handling keyboard input Detecting key presses Dealing with buffered keyboard input Handling mouse input Reading the mouse position Working with relative mouse motion Handling joystick input 145 146 Chapter 5 I I I Programming the Keyboard, Mouse, and Joystick Handling joystick controller movement Handling joystick button presses Handling Keyboard Input Allegro... Figure 5 .2 Figure 5.1 The gate symbols have yet to be deciphered Are you up to the challenge? Handling Keyboard Input Figure 5 .2 Opening a gateway to another world—speculative fantasy or a real possibility? #include “allegro.h” #define WHITE makecol (25 5 ,25 5 ,25 5) #define BLUE makecol(64,64 ,25 5) #define RED makecol (25 5,64,64) typedef struct POINT { int x, y; } POINT; POINT coords[] = { {25 , 23 5}, {15, 130 },... keyboard routines in Allegro, you must initialize the keyboard handler with the install_keyboard function int install_keyboard(); If you try to use the keyboard routines before initializing, the program will likely crash (or at best, it won’t respond to the keyboard) Once you have initialized the keyboard handler, there is no need to uninitialize it—that is handled by Allegro via the allegro_exit function... systems that don’t support the keyboard interrupt service routine Why would this be the case? Allegro is a multi-threaded library When you call allegro_init and functions such as install_keyboard, Allegro creates several threads to handle events, scroll the screen, draw sprites, and so on int poll_keyboard(); Handling Keyboard Input When you first call poll_keyboard, Allegro switches to polled mode, after... keys on computer systems are supported by name using constant key values defined in the Allegro library header files If you want to see all of the key definitions yourself, look in the Allegro library folder for a header file called keyboard.h, in which all the keys are defined Note also that Allegro defines individual keys, not ASCII codes, so the main Table 5.1 Common Key Codes numeric keys are not... your game (Windows, Linux, Mac, and so on) However, that abstraction does not take anything away from the inherent capabilities of any system because the library is custom-written for each platform The Windows version of Allegro utilizes DirectInput for the keyboard handler Since there really is no magic to the subject, let’s just jump right in and work with the keyboard Before you can start using the... games, primarily due to modern operating systems Allegro supports both ANSI (one- byte) and Unicode (two-byte) character systems (By the way, ANSI stands for American National Standards Institute and ASCII stands for American Standard Code for Information Interchange.) The Keyboard Handler Allegro abstracts the keyboard from the operating system so the generic keyboard routines will work on any computer system... 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));... and prepare the program for the actual game That is where Allegro truly shines—by abstracting the logistical 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 . 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. 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. 100 #define MAXSPEED 2 #define BULLETSPEED 10 #define TAN makecol (25 5 ,24 2,169) #define CAMO makecol(64,1 42, 66) #define BURST makecol (25 5,189, 73) //define tank structure struct tagTank { int x,y; int

Ngày đăng: 12/08/2014, 19:20

Từ khóa liên quan

Mục lục

  • CH 4 Writing Your First Allegro Game

  • CH 5 Programming The Keyboard, Mouse, and Joystick

  • CH 6 Introduction to Game Design

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan