Building the UFO 2 Program Example


Hour 6, "Controlling Games with the Keyboard and Mouse," guided you through the design and development of an interesting little program that allowed you to control a flying saucer using the keyboard and mouse. The remainder of this hour focuses on adding joystick support to the UFO program example to create a new version of the program called UFO 2. In addition to providing joystick support, you also enhance the program a little by adding a thrust image to the flying saucer and a hyperspace feature. "Thrusting" in this case simply involves drawing a flying saucer with a flame shooting out of the bottom, whereas going into hyperspace involves repositioning the saucer at a random location on the game screen.

Writing the Program Code

The code for the UFO 2 program starts with the UFO.h header file, which includes a couple of changes from its previous version:

 Bitmap*     _pSaucer[2]; BOOL        _bSaucerFlame; 

The first change to this code from the previous version of the program is the modification of the _pSaucer global variable to being an array of two bitmaps, as opposed to one. This is necessary because the thrust bitmap has now been added to show the flying saucer with a flame shooting out. The other change to the code involves the addition of the _bSaucerFlame variable, which keeps track of whether the saucer is to be displayed with a flame.

The GameInitialize() function is the first game function to revisit for the UFO 2 program. The only change to this code from the previous version is the addition of the call to the game engine's InitJoystick() method, which is necessary to get the joystick primed and ready for action:

 pGame->InitJoystick(); 

The GameStart() function also has changed a little, as shown in Listing 7.5.

Listing 7.5 The GameStart() Function Initializes the Background and Flying Saucer Bitmaps
 1: void GameStart(HWND hWindow)  2: {  3:   // Seed the random number generator  4:   srand(GetTickCount());  5:  6:   // Create and load the background and saucer bitmaps  7:   HDC hDC = GetDC(hWindow);  8:   _pBackground = new Bitmap(hDC, IDB_BACKGROUND, _hInstance);  9:   _pSaucer[0] = new Bitmap(hDC, IDB_SAUCER, _hInstance); 10:   _pSaucer[1] = new Bitmap(hDC, IDB_SAUCERFLAME, _hInstance); 11: 12:   // Set the initial saucer position and speed 13:   _iSaucerX = 250 - (_pSaucer[0]->GetWidth() / 2); 14:   _iSaucerY = 200 - (_pSaucer[0]->GetHeight() / 2); 15:   _iSpeedX = 0; 16:   _iSpeedY = 0; 17: } 

Because the hyperspace feature of UFO 2 requires the calculation of a random location on the screen, it's necessary to seed the random number generator (line 4). This function also loads the new flaming saucer image (line 10).

Earlier, I mentioned that it's important for any program that supports joysticks to properly capture and release the joystick in response to the main program window being activated and deactivated. In the case of UFO 2, this takes place in the GameActivate() and GameDeactivate() functions, which are shown in Listing 7.6.

Listing 7.6 The GameActivate() and GameDeactivate() Function Captures and Releases the Joystick in Response to the Main Program Window Being Activated and Deactivated
 1: void GameActivate(HWND hWindow)  2: {  3:   // Capture the joystick  4:   _pGame->CaptureJoystick();  5: }  6:  7: void GameDeactivate(HWND hWindow)  8: {  9:   // Release the joystick 10:   _pGame->ReleaseJoystick(); 11: } 

The GameActivate() function simply calls the CaptureJoystick() method of the game engine to capture the joystick (line 4). Similarly, the joystick is released in GameDeactivate() with a quick call to the ReleaseJoystick() method.

If you're curious as to how the thrusting flying saucer is drawn, well wonder no more! The GamePaint() function handles drawing the appropriate flying saucer depending on the value of the _bSaucerFlame global variable, as shown in Listing 7.7.

Listing 7.7 The GamePaint() Function Draws the Background and Flying Saucer Bitmaps, Making Sure to Determine Which Flying Saucer Bitmap to Draw
 1: void GamePaint(HWND hWindow)  2: {  3:   // Draw the background and saucer bitmaps  4:   _pBackground->Draw(hDC, 0, 0);  5:   _pSaucer[_bSaucerFlame ? 1:0]->Draw(hDC, _iSaucerX, _iSaucerY, TRUE);  6: } 

As the listing reveals, the _bSaucerFlame variable directly determines which flying saucer is drawn (line 5). Of course, you're probably still curious as to how this variable gets modified in the first place; that's where the joystick enters the picture.

If you recall from earlier, a program that uses our super slick game engine to process joystick input must provide its own HandleJoystick() function to perform its own processing of joystick input. In this case, the HandleJoystick() function is responsible for altering the speed of the flying saucer in response to directional joystick movements, as well as controlling the thrust and hyperspace features of the flying saucer when the two joystick buttons are pressed. Listing 7.8 shows how the HandleJoystick() function carries out these tasks .

Listing 7.8 The HandleJoystick() Function Takes Care of Processing Joystick Input and Altering the Flying Saucer Appropriately
 1: void HandleJoystick(JOYSTATE jsJoystickState)  2: {  3:   // Check horizontal movement  4:   if (jsJoystickState & JOY_LEFT)  5:     _iSpeedX = max(-_iMAXSPEED, _iSpeedX - 2);  6:   else if (jsJoystickState & JOY_RIGHT)  7:     _iSpeedX = min(_iMAXSPEED, _iSpeedX + 2);  8:  9:   // Check vertical movement 10:   if (jsJoystickState & JOY_UP) 11:     _iSpeedY = max(-_iMAXSPEED, _iSpeedY - 2); 12:   else if (jsJoystickState & JOY_DOWN) 13:     _iSpeedY = min(_iMAXSPEED, _iSpeedY + 2); 14: 15:   // Check primary joystick button 16:   _bSaucerFlame = (jsJoystickState & JOY_FIRE1); 17: 18:   // Check secondary joystick button 19:   if (jsJoystickState & JOY_FIRE2) 20:   { 21:     // Force the flying saucer into hyperspace 22:     _iSaucerX = rand() % (500 - _pSaucer[0]->GetWidth()); 23:     _iSaucerY = rand() % 320; 24:   } 25: } 

Seeing as how the HandleJoystick() function is essentially your only real communication link to the joystick in the UFO 2 program, it's really quite simple. The first block of code in the function checks to see if a horizontal movement has occurred ”in which case, the X component of the flying saucer's speed if modified (lines 4 “7). Similarly, the second block of code performs the same processing on vertical joystick movement (lines 10 “13). The _bSaucerFlame global variable is then set using the state of the first joystick button (line 16). And finally, the hyperspace feature is carried out in response to the second joystick button being pressed (lines 19 “24).

Testing the Finished Product

If you haven't done so already, I encourage you to plug in your joystick and take the UFO 2 program for a test spin. You'll hopefully find that the joystick controls for the program have a surprisingly good feel considering that the joystick handling code in the program is relatively simple. Try pressing the two primary buttons on the joystick to get a feel for the thrust and hyperspace features of the program. Figure 7.7 shows the flying saucer as it appears with the flaming thrust beneath it.

Figure 7.7. The flying saucer in the UFO 2 program example shows off its new thrusting abilities .

graphics/07fig07.gif

graphics/bulb.gif

If the flying saucer immediately starts moving without you touching the joystick, it's a pretty good sign that your joystick needs to be calibrated. Please revisit the earlier section "Calibrating Joysticks," to find out how to calibrate your joystick and eliminate this problem.


Granted, you might have a valid concern as to why the flying saucer visually thrusts but doesn't seem to have any additional lift when you press the thrust button. This is something I challenge you to solve as an exercise at the end of the hour. You might also have noticed that hyperspace is quite sensitive. In fact, the hyperspace feature reveals how fast the game engine's joystick processing actually is.



Sams Teach Yourself Game Programming in 24 Hours
Sams Teach Yourself Game Programming in 24 Hours
ISBN: 067232461X
EAN: 2147483647
Year: 2002
Pages: 271

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net