Building the Space Out 3 Game


You've already learned that in some ways demo mode is similar to a splash screen because it appears in a game when the game is not actually being played . Unlike a splash screen, however, demo mode is responsible for displaying sprites and enabling them to interact to some degree. Adding a demo mode to the Space Out game represents a programming challenge, but one that isn't too terribly difficult to solve. The next few sections lead you through the modifications required in the game to add a demo mode. The new version of the game you'll be creating is called Space Out 3.

Writing the Game Code

The best place to start with the code for the Space Out 3 game is the SpaceOut.h header file, which includes a couple of new global variables. Demo mode for the game requires two new global variables ; one of which replaces the _bSplash global variable that you added in the last hour for the splash screen. Following are the new global variables necessary to support demo mode in the Space Out 3 game:

 BOOL _bDemo; int  _iGameOverDelay; 

The first variable, _bDemo , is very similar to the _bSplash variable in the Space Out 2 game from the previous hour. In fact, it serves virtually the same purpose in this game, except that demo mode impacts more code than the splash screen. The _iGameOverDelay global variable is used to provide a delay between when a game ends and when the game enters demo mode. This allows the player to take a moment and realize that the game is over before it cuts back to demo mode.

The first function of particular interest in the Space Out 3 game is the GameStart() function, which shouldn't come as too much of a surprise. The only change to the GameStart() function is the initialization of the _bDemo variable.

The GamePaint() function is where the code for the Space Out 3 game starts to diverge more significantly from the Space Out 2 game. However, the change is still somewhat subtle in that all the same code is here, it's just organized a little differently. Take a look at Listing 23.1 to see what I mean.

Listing 23.1 The GamePaint() Function Draws the Game Graphics While Taking into Consideration Demo Mode
 1: void GamePaint(HDC hDC)  2: {  3:   // Draw the background  4:   _pBackground->Draw(hDC);  5:  6:   // Draw the desert bitmap  7:   _pDesertBitmap->Draw(hDC, 0, 371);  8:  9:   // Draw the sprites 10:   _pGame->DrawSprites(hDC); 11: 12:   if (_bDemo) 13:   { 14:     // Draw the splash screen image 15:     _pSplashBitmap->Draw(hDC, 142, 100, TRUE); 16:   } 17:   else 18:   { 19:     // Draw the score 20:     TCHAR szText[64]; 21:     RECT  rect = { 460, 0, 510, 30 }; 22:     wsprintf(szText, "%d", _iScore); 23:     SetBkMode(hDC, TRANSPARENT); 24:     SetTextColor(hDC, RGB(255, 255, 255)); 25:     DrawText(hDC, szText, -1, &rect, DT_SINGLELINE  DT_RIGHT  26:       DT_VCENTER); 27: 28:     // Draw the number of remaining lives (cars) 29:     for (int i = 0; i < _iNumLives; i++) 30:       _pSmCarBitmap->Draw(hDC, 520 + (_pSmCarBitmap->GetWidth() * i), 31:         10, TRUE); 32: 33:     // Draw the game over message, if necessary 34:     if (_bGameOver) 35:       _pGameOverBitmap->Draw(hDC, 170, 100, TRUE); 36:   } 37: } 

The GameCycle() function in Space Out 3 looks a lot like its predecessor, but there is a significant change you should pay close attention to. The change I'm talking about involves the fact that the sprites are drawn regardless of whether the game is in demo mode (line 10). In fact, all that is not drawn in demo mode is the score (lines 20 “26), the number of remaining lives (lines 29 “31), and the game over message (lines 34 and 35). Also notice that the same splash screen image is displayed when the game is in demo mode (lines 12 “16), which means that the game is combining demo mode with the splash screen. This isn't a problem, but it does mean that the game is being demonstrated behind the splash screen image.

The GameCycle() function must be modified to accommodate demo mode as well. In fact, the GameCycle() function is where the timing delay is established that displays the game over screen for a period of time before reverting back to demo mode when a game ends. Listing 23.2 shows the code for the new version of the GameCycle() function.

Listing 23.2 The GameCycle() Function Establishes a Timing Delay Before Moving to Demo Mode from the Game Over Screen
 1: void GameCycle()  2: {  3:   if (!_bGameOver)  4:   {  5:     if (!_bDemo)  6:     {  7:       // Randomly add aliens  8:       if ((rand() % _iDifficulty) == 0)  9:         AddAlien(); 10:     } 11: 12:     // Update the background 13:     _pBackground->Update(); 14: 15:     // Update the sprites 16:     _pGame->UpdateSprites(); 17: 18:     // Obtain a device context for repainting the game 19:     HWND  hWindow = _pGame->GetWindow(); 20:     HDC   hDC = GetDC(hWindow); 21: 22:     // Paint the game to the offscreen device context 23:     GamePaint(_hOffscreenDC); 24: 25:     // Blit the offscreen bitmap to the game screen 26:     BitBlt(hDC, 0, 0, _pGame->GetWidth(), _pGame->GetHeight(), 27:       _hOffscreenDC, 0, 0, SRCCOPY); 28: 29:     // Cleanup 30:     ReleaseDC(hWindow, hDC); 31:   } 32:   else 33:     if (--_iGameOverDelay == 0) 34:     { 35:       // Stop the music and switch to demo mode 36:       _pGame->PauseMIDISong(); 37:       _bDemo = TRUE; 38:       NewGame(); 39:     } 40: } 

In addition to changing the _bSplash variable to _bDemo (line 5), the GameCycle() function establishes a timing delay for the game over screen (lines 33 “39). When this delay finishes counting down, it means that the game over message has been displayed long enough and it's okay to go ahead and put the game in demo mode. This is accomplished by setting the _bDemo variable to TRUE (line 37), and then calling the NewGame() function to add a few alien sprites to demo mode (line 38). Notice that the MIDI music isn't actually stopped until the game switches to demo mode (line 36), which makes sense when you consider that the game over screen is still a reflection on the last game played.

Demo mode also impacts the HandleKeys() function in the Space Out 3 game, as you can see in Listing 23.3.

Listing 23.3 The HandleKeys() Function Supports Demo Mode by Changing the Value of the _bDemo Variable if the Game Is Exiting Demo Mode to Start a New Game
 1: void HandleKeys()  2: {  3:   if (!_bGameOver && !_bDemo)  4:   {  5:     // Move the car based upon left/right key presses  6:     POINT ptVelocity = _pCarSprite->GetVelocity();  7:     if (GetAsyncKeyState(VK_LEFT) < 0)  8:     {  9:       // Move left 10:       ptVelocity.x = max(ptVelocity.x - 1, -4); 11:       _pCarSprite->SetVelocity(ptVelocity); 12:     } 13:     else if (GetAsyncKeyState(VK_RIGHT) < 0) 14:     { 15:       // Move right 16:       ptVelocity.x = min(ptVelocity.x + 2, 6); 17:       _pCarSprite->SetVelocity(ptVelocity); 18:     } 19: 20:     // Fire missiles based upon spacebar presses 21:     if ((++_iFireInputDelay > 6) && GetAsyncKeyState(VK_SPACE) < 0) 22:     { 23:       // Create a new missile sprite 24:       RECT  rcBounds = { 0, 0, 600, 450 }; 25:       RECT  rcPos = _pCarSprite->GetPosition(); 26:       Sprite* pSprite = new Sprite(_pMissileBitmap, rcBounds, BA_DIE); 27:       pSprite->SetPosition(rcPos.left + 15, 400); 28:       pSprite->SetVelocity(0, -7); 29:       _pGame->AddSprite(pSprite); 30: 31:       // Play the missile (fire) sound 32:       PlaySound((LPCSTR)IDW_MISSILE, _hInstance, SND_ASYNC  33:         SND_RESOURCE  SND_NOSTOP); 34: 35:       // Reset the input delay 36:       _iFireInputDelay = 0; 37:     } 38:   } 39: 40:   // Start a new game based upon an Enter (Return) key press 41:   if (GetAsyncKeyState(VK_RETURN) < 0) 42:     if (_bDemo) 43:     { 44:       // Switch out of demo mode to start a new game 45:       _bDemo = FALSE; 46:       NewGame(); 47:     } 48:     else if (_bGameOver) 49:     { 50:       // Start a new game 51:       NewGame(); 52:     } 53: } 

The only changes in this function involve renaming the _bSplash variable to _bDemo (lines 3, 42, and 45).

The new code in the SpriteCollision() function involves the timing delay for the game over screen. More specifically , the _iGameOverDelay variable is set to 150 , which means that the game screen will be displayed for 150 cycles before the game returns to demo mode:

 if (--_iNumLives == 0) {   // Play the game over sound   PlaySound((LPCSTR)IDW_GAMEOVER, _hInstance, SND_ASYNC      SND_RESOURCE);   _bGameOver = TRUE;   _iGameOverDelay = 150; } 

Any idea how much time 150 cycles is? You know that the frame rate for the game is set at 30 frames per second, which is the same thing as saying that the game goes through 30 cycles per second. Knowing this, you can divide 150 by 30 to arrive at a delay of 5 seconds for the game over screen. Pretty neat, right?

The SpriteDying() function involves an interesting change related to demo mode that you might not have thought about. Analyze Listing 23.4 and see if you can figure out why the change is necessary.

Listing 23.4 The SpriteDying() Function Makes Sure Not to Play the Sound of Exploding Alien Missiles When the Game Is in Demo Mode
 1: void SpriteDying(Sprite* pSprite)  2: {  3:   // See if an alien missile sprite is dying  4:   if (pSprite->GetBitmap() == _pBMissileBitmap   5:     pSprite->GetBitmap() == _pJMissileBitmap   6:     pSprite->GetBitmap() == _pTMissileBitmap)  7:   {  8:     // Play the small explosion sound  9:     if (!_bDemo) 10:       PlaySound((LPCSTR)IDW_SMEXPLODE, _hInstance, SND_ASYNC  11:         SND_RESOURCE  SND_NOSTOP); 12: 13:     // Create a small explosion sprite at the missile's position 14:     RECT rcBounds = { 0, 0, 600, 450 }; 15:     RECT rcPos = pSprite->GetPosition(); 16:     Sprite* pSprite = new Sprite(_pSmExplosionBitmap, rcBounds); 17:     pSprite->SetNumFrames(8, TRUE); 18:     pSprite->SetPosition(rcPos.left, rcPos.top); 19:     _pGame->AddSprite(pSprite); 20:   } 21: } 

When you think about it, demo mode for a computer game shouldn't be something that annoys you, which means that it's probably best for it to not make a bunch of noise. Because the aliens in demo mode will be firing missiles that explode when they hit the ground, it's necessary to quiet the missiles in the SpriteDying() function so that they don't make noise in demo mode (lines 9 “11).

The NewGame() function is the last of the functions impacted by the switch to demo mode in the Space Out 3 game, and it's also the most interesting. Listing 23.5 shows the code for the NewGame() function.

Listing 23.5 The NewGame() Function Adds a Few Aliens to the Game When It Is in Demo Mode
 1: void NewGame()  2: {  3:   // Clear the sprites  4:   _pGame->CleanupSprites();  5:  6:   // Initialize the game variables  7:   _iFireInputDelay = 0;  8:   _iScore = 0;  9:   _iNumLives = 3; 10:   _iDifficulty = 80; 11:   _bGameOver = FALSE; 12: 13:   if (_bDemo) 14:   { 15:     // Add a few aliens to the demo 16:     for (int i = 0; i < 6; i++) 17:       AddAlien(); 18:   } 19:   else 20:   { 21:     // Create the car sprite 22:     RECT rcBounds = { 0, 0, 600, 450 }; 23:     _pCarSprite = new Sprite(_pCarBitmap, rcBounds, BA_WRAP); 24:     _pCarSprite->SetPosition(300, 405); 25:     _pGame->AddSprite(_pCarSprite); 26: 27:     // Play the background music 28:     _pGame->PlayMIDISong(TEXT("Music.mid")); 29:   } 30: } 

Although you might think of the NewGame() function as only being used to start a new game that you're going to play, it is also used to start a new demo game. A demo game is a "game" that includes a few aliens and nothing else. In other words, there is no car, which eliminates the difficulty of trying to simulate a human player in code. Fortunately, the aliens in the Space Out game are interesting enough that they do a pretty good job of conveying the premise of the game without having to throw in the car.

The NewGame() function actually adds six alien sprites to the game engine when the game is in demo mode (lines 13 “18). One neat thing about this code is that the AddAlien() function is designed to add a random alien, which means that demo mode is different each time the game goes into it; the six aliens added are always different. Granted, this demo mode could have been made more interesting by adding the car sprite and having it fight back with the aliens, but for the sake of simplicity, you can't help but like the approach of just adding a few aliens and letting them cruise around the game screen firing missiles on their own.

Testing the Finished Product

Testing demo mode in the Space Out 3 game is a little like testing the splash screen in Space Out 2 ”just launch the game and watch it go! Figure 23.1 shows the Space Out 3 demo mode with the aliens flying around having a good time.

Figure 23.1. Demo mode in the Space Out 3 game involves several aliens flying around the game screen behind the splash screen image.

graphics/23fig01.jpg

As you can see, the aliens in demo mode help to demonstrate how the game is played even though they aren't interacting directly with a simulated player through the car sprite. Like I said earlier, the car sprite would be a very nice improvement for demo mode, but the idea here is to keep things simple. Any time you can achieve a desired effect with less code, and therefore less complexity, it is a good thing.

Figure 23.2 shows a game that has just ended in Space Out 3. In this figure, the game over screen is shown while the time delay is ticking away.

Figure 23.2. When a game finishes in Space Out 3, the game over screen is displayed for a few seconds.

graphics/23fig02.gif

The game over screen in Space Out 3 is displayed for a few seconds before the game goes back to demo mode, as shown in Figure 23.3.

Figure 23.3. After the game over screen has been shown for a few seconds, the Space Out 3 game reverts back to demo mode, although each demo mode is a little different.

graphics/23fig03.jpg

I'm showing a shot of demo mode one more time just to demonstrate how it varies each time the game goes into it. If you compare this figure with Figure 23.1, you'll notice that the aliens are distributed a little differently. This is a subtle detail of demo mode that helps to make the game a little more interesting.



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