1: void GameEnd() 2: { 3: // Close the MIDI player for the background music 4: _pGame->CloseMIDIPlayer(); 5: 6: // Cleanup the offscreen device context and bitmap 7: DeleteObject(_hOffscreenBitmap); 8: DeleteDC(_hOffscreenDC); 9: 10: // Cleanup the bitmaps 11: delete _pGroundBitmap; 12: delete _pTargetBitmap; 13: delete _pCityBitmap; 14: delete _pMeteorBitmap; 15: delete _pMissileBitmap; 16: delete _pExplosionBitmap; 17: delete _pGameOverBitmap; 18: 19: // Cleanup the background 20: delete _pBackground; 21: 22: // Cleanup the sprites 23: _pGame->CleanupSprites(); 24: 25: // Cleanup the game engine 26: delete _pGame; 27: } The first step in the GameEnd() function is to close the MIDI player (line 4). The bitmaps and sprites are then wiped away (lines 7 20), as well as the background (line 20). Finally, the sprites are cleaned up (line 23) and the game engine is destroyed (line 26). The game screen in the Meteor Defense game is painted by the GamePaint() function, which is shown in Listing 19.5. Listing 19.5 The GamePaint() Function Draws the Background, the Ground Bitmap, the Sprites, the Score, and the Game Over Message 1: void GamePaint(HDC hDC) 2: { 3: // Draw the background 4: _pBackground->Draw(hDC); 5: 6: // Draw the ground bitmap 7: _pGroundBitmap->Draw(hDC, 0, 398, TRUE); 8: 9: // Draw the sprites 10: _pGame->DrawSprites(hDC); 11: 12: // Draw the score 13: TCHAR szText[64]; 14: RECT rect = { 275, 0, 325, 50 }; 15: wsprintf(szText, “%d”, _iScore); 16: SetBkMode(hDC, TRANSPARENT); 17: SetTextColor(hDC, RGB(255, 255, 255)); 18: DrawText(hDC, szText, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); 19: 20: // Draw the game over message, if necessary 21: if (_bGameOver) 22: _pGameOverBitmap->Draw(hDC, 170, 150, TRUE); 23: } This GamePaint() function is responsible for drawing all the graphics for the game. The function begins by drawing the starry background (line 4), followed by the ground image (line 7). The sprites are drawn next (line 10), followed by the score (lines 13 18). Notice that the score text is set to white (line 17), whereas the background is set to transparent for drawing the score so that the starry sky shows through the numbers in the score (line 16). The GamePaint() function finishes up by drawing the game over image, if necessary (lines 21 22). The GameCycle() function works closely with GamePaint() to update the game’s sprites and
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Clan Web Hosting services
23: Bitmap* _pMeteorBitmap; 24: Bitmap* _pMissileBitmap; 25: Bitmap* _pExplosionBitmap; 26: Bitmap* _pGameOverBitmap; 27: StarryBackground* _pBackground; 28: Sprite* _pTargetSprite; 29: int _iNumCities, _iScore, _iDifficulty; 30: BOOL _bGameOver; 31: 32: //—————————————————————-33: // Function Declarations 34: //—————————————————————-35: void NewGame(); 36: void AddMeteor(); As the listing reveals, the global variables for the Meteor Defense game largely consist of the different bitmaps that are used throughout the game. The starry background for the game is declared after the bitmaps (line 27), followed by the crosshair target sprite (line 28). Member variables storing the number of remaining cities, the score, and the difficulty level are then declared (line 29), along with the familiar game over Boolean variable (line 30). The NewGame() function declared in the MeteorDefense.h file is important because it is used to set up and start a new game (line 35). Unlike the GameStart() function, which performs critical initialization tasks such as loading bitmaps, the NewGame() function deals with actually starting a new game once everything else is in place. The AddMeteor() function is a support function used to simplify the task of adding meteor sprites to the game (line 36). You find out more about how these functions work later in the hour. The initialization of the game variables primarily takes place in the GameStart() function, which is shown in Listing 19.3. Listing 19.3 The GameStart() Function Initializes the Bitmaps and Background for the Game, and Calls the NewGame() Function 1: void GameStart(HWND hWindow) 2: { 3: // Seed the random number generator 4: srand(GetTickCount()); 5: 6: // Create the offscreen device context and bitmap 7: _hOffscreenDC = CreateCompatibleDC(GetDC(hWindow)); 8: _hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow), 9: _pGame->GetWidth(), _pGame->GetHeight()); 10: SelectObject(_hOffscreenDC, _hOffscreenBitmap); 11: 12: // Create and load the bitmaps 13: HDC hDC = GetDC(hWindow); 14: _pGroundBitmap = new Bitmap(hDC, IDB_GROUND, _hInstance); 15: _pTargetBitmap = new Bitmap(hDC, IDB_TARGET, _hInstance); 16: _pCityBitmap = new Bitmap(hDC, IDB_CITY, _hInstance); 17: _pMeteorBitmap = new Bitmap(hDC, IDB_METEOR, _hInstance); 18: _pMissileBitmap = new Bitmap(hDC, IDB_MISSILE, _hInstance); 19: _pExplosionBitmap = new Bitmap(hDC, IDB_EXPLOSION, _hInstance); 20: _pGameOverBitmap = new Bitmap(hDC, IDB_GAMEOVER, _hInstance); 21: 22: // Create the starry background 23: _pBackground = new StarryBackground(600, 450); 24: 25: // Play the background music 26: _pGame->PlayMIDISong(TEXT(”Music.mid”)); 27: 28: // Start the game 29: NewGame(); 30: } After loading the bitmaps for the game (lines 14 20) and creating the starry background (line 23), the GameStart() function starts playing the background music (line 26). The function then finishes by calling the NewGame() function to start a new game (line 29). The GameEnd() function plays a complementary role to the GameStart() function and cleans up after the game. Listing 19.4 contains the code for the GameEnd() function. Listing 19.4 The GameEnd() Function Cleans Up After the Game
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Clan Web Hosting services
10: … 11: } If you recall, the Sprite::Update() method is actually a large method, so I’m only showing you the beginning of it here because this is all that has changed. The method now checks the value of the m_bDying member variable (line 4), and then returns SA_KILL if it is set to TRUE (line 5). If you recall from earlier in the book, SA_KILL is a sprite action you created that notifies the game engine when a sprite needs to be killed. Prior to now, it was only used to kill a sprite when it encounters a boundary. Simply killing a sprite isn’t quite sufficient when it comes to improving the game engine for future games. You’ll find out later in the hour that it can be incredibly useful to know when a sprite is being destroyed regardless of why it is being destroyed. For example, when a meteor sprite is destroyed, you can create an explosion sprite to show the destruction of the meteor. The notification of a sprite being killed is made possible through the SpriteDying() function, which is called whenever a sprite is dying: void SpriteDying(Sprite* pSprite); Understand that the SpriteDying() function is a function that you must provide as part of a game. In other words, it is designed to house game-specific code that responds to particular types of sprites dying within a game. The final change to the game engine to support the new sprite killing features appears within the GameEngine class in the UpdateSprites() method, which now includes a call to SpriteDying() that notifies a game of a sprite being destroyed and removed from the sprite list. This gives the game a chance to respond to the sprite’s demise and carry out any appropriate actions. Building the Game You can breathe a sigh of relief because you’re finished making changes to the game engine for a little while. However, the real challenge of putting together the Meteor Defense game now awaits you. Fortunately, the game isn’t too difficult to understand because you’ve already worked through a reasonably detailed game design. The next few sections guide you through the development of the game’s code and resources. Writing the Game Code The code for the Meteor Defense game begins in the MeteorDefense.h header file, which is responsible for declaring the global variables used throughout the game, as well as a couple of useful functions. Listing 19.2 contains the code for this file. Listing 19.2 The MeteorDefense.h Header File Declares Global Variables and Game-Specific Functions for the Meteor Defense Game 1: #pragma once 2: 3: //—————————————————————-4: // Include Files 5: //—————————————————————-6: #include 7: #include “Resource.h” 8: #include “GameEngine.h” 9: #include “Bitmap.h” 10: #include “Sprite.h” 11: #include “Background.h” 12: 13: //—————————————————————-14: // Global Variables 15: //—————————————————————-16: HINSTANCE _hInstance; 17: GameEngine* _pGame; 18: HDC _hOffscreenDC; 19: HBITMAP _hOffscreenBitmap; 20: Bitmap* _pGroundBitmap; 21: Bitmap* _pTargetBitmap; 22: Bitmap* _pCityBitmap;
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost PHP Web Hosting services
finished? The real problem I’m talking about here is that of allowing a sprite to animate through one cycle and then go away. The game engine doesn’t currently support this feature, but it’s not too difficult to add. Without this feature, there is no straightforward way to use a sprite such as an explosion that must cycle through its animation once and then exit the game. The key to adding this feature to the game engine is including a couple of new variables to the Sprite class: BOOL m_bDying; BOOL m_bOneCycle; The m_bDying member variable determines whether a sprite has been flagged as dying. In other words, normal sprites have their m_bDying variable set to FALSE, whereas a sprite on the way out has it set to TRUE. The cool thing about this variable is that it allows you to kill a sprite at any time by simply setting the variable to TRUE. Of course, this requires some additional code in both the Sprite and GameEngine classes to make it actually work. The second member variable, m_bOneCycle, indicates whether a sprite should animate once through its frames and then kill itself. Because this variable only makes sense within the context of a frame animated sprite, it is set when you call the SetNumFrames() method. You see how the SetNumFrames() method is modified to account for the m_bOneCycle variable in a moment. For now, let’s take a look at how the two new Sprite member variables are initialized in the Sprite() constructors: m_bDying = FALSE; m_bOneCycle = FALSE; As you might expect, the default value of both variables is FALSE, which makes sprites behave normally. The m_bDying member variable can be set to TRUE through the Kill() method, which is really just an accessor method because all it does is set the variable: void Kill() { m_bDying = TRUE; }; This method now gives you a clean and efficient means of killing any sprite with the security of knowing that it will be properly removed from the sprite list maintained by the game engine. This is a crucial aspect of destroying a sprite because the sprite list in the game engine would go haywire if you were to simply delete a sprite from memory and not remove it from the list. The Kill() method provides a clean interface for carrying out this task. Whereas the Kill() method provides an immediate way to kill a sprite that can be useful in some situations, the more elegant approach is to allow a sprite to kill itself when it finishes cycling through its frame animations. The UpdateFrame() method now supports this feature by examining the m_bOneCycle variable, and then setting the m_bDying variable accordingly. The original version of this method simply set the m_iCurFrame variable to 0 so that the animation starts over, which this method still does if the m_bOneCycle variable is FALSE. However, if the m_bOneCycle variable is TRUE, the m_bDying variable is set to TRUE, which starts the sprite on a path to destruction. The m_bOneCycle variable is set in the SetNumFrames() method, which now looks like this: void SetNumFrames(int iNumFrames, BOOL bOneCycle = FALSE); As you can see, the SetNumFrames() method now includes a second argument for setting the m_bOneCycle member variable. To help make the transition to using the new version of the method easier, the bOneCycle argument is given a default value of FALSE. This allows you to use the method just as you’ve already grown accustomed. However, if you want to create a sprite that cycles through its animation once and then goes away, just pass TRUE as the second argument to SetNumFrames(). Getting back to the killing of a sprite via the m_bDying member variable, the place where the murder plot unfolds is in the Update() method, which is shown in Listing 19.1. Listing 19.1 The Sprite::Update() Method Kills a Sprite if It Is Flagged as Dying 1: SPRITEACTION Sprite::Update() 2: { 3: // See if the sprite needs to be killed 4: if (m_bDying) 5: return SA_KILL; 6: 7: // Update the frame 8: UpdateFrame(); 9:
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost PHP Web Hosting services
the ground image. The missile and meteor sprites move around on top of the starry background, while the score is displayed centered near the top of the game screen. One last piece of the game not shown in the figure is the target sprite that you guide with the mouse, much like the target sprite you saw in the Battle Office game from earlier in the book. Now that you understand the basics of the game and how it is laid out, it’s time to examine what kinds of sprites need to be used. Following is a list of the sprites that go into the Meteor Defense game: City sprites Meteor sprites Missile sprites Explosion sprites Target sprite The city sprites appear along the bottom of the screen, as shown in Figure 19.1. The meteor sprites are created at random, and fall from the top of the screen toward the cities at the bottom. The missile sprites are fired from the gun locations on the screen upward toward the meteors. I haven’t mentioned the explosion sprites yet, and that’s because there isn’t a whole lot to them. An explosion sprite appears whenever a meteor is blown up or a city is destroyed and involves displaying an animation of a fiery explosion. Finally, the target sprite appears as a crosshair that you guide with the mouse to aim missiles that you launch via the left mouse button. Beyond the sprites, the Meteor Defense game also requires several bitmaps. Following are the seven bitmap images required of the game: Background ground image City image Meteor image (animated) Missile image Explosion image (animated) Crosshair target image Game over image These images should make sense based on the description of the game and the sprites that you’ve learned about. With the graphical objects squared away, you need to turn your attention to the other information that must be maintained by the game. For example, the score needs to be maintained throughout the game, as well as the number of remaining cities; the game ends when all four of the cities are destroyed by meteors. This is a game in which it is important to increase the difficulty level as the game progresses. So, it’s important to store the difficulty level of the game and gradually increase it as the player continues to keep his cities protected. The last critical piece of information to maintain is a Boolean variable to keep track of whether the game is over. To recap, the design of the Meteor Defense game has led us to the following pieces of information that must be managed by the game: The number of cities remaining The score The difficulty level A Boolean game over variable With this information in mind, you’re now almost ready to take the big step of assembling the code for the Meteor Defense game. However, there is a modification you need to make to the game engine to support a critical feature of the game, and ultimately improve the game engine for future games. Enhancing Sprites in the Game Engine If you’re a particularly inquisitive person, you might have wondered how exactly the explosion sprites will work in the game. The animation part is simple enough because the Sprite class in the game engine now allows you to flip through a series of animation images. However, an explosion sprite must cycle through its animation frames and then immediately go away, which sounds simple but presents a problem for the game engine. The problem is that there currently is no mechanism for a sprite to hide or kill itself automatically when it is no longer needed. Granted, you can kill a sprite from within the game code, but how would you keep track of when the frame animation for an explosion is
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Clan Web Hosting services
bottom. Your job is to fire upon the missiles and destroy them before they reach the cities. Although Missile Command made for an interesting game in the era of the hit movie War Games, the threat of nuclear attack is somewhat diminished these days, at least in terms of what most of us perceive as a realistic threat. However, there has been increasing talk in the past few years of the possibility of a meteor striking the Earth and causing major damage. The premise of the game you develop in this hour is similar to Missile Command in that you’re defending helpless cities against an incoming threat. In this case, however, the threat is giant meteors, not nuclear warheads. The Meteor Defense game employs a game play strategy similar to Missile Command in that you fire missiles at the incoming meteors to stop them from destroying the cities below. As you’ll find out, the critical skill to becoming a good player at Meteor Defense (and Missile Command as well) is learning how to target a meteor and give a missile time to get there. In other words, you often have to lead a meteor by a certain distance to give the missile time to get there and make contact. The object of Meteor Defense is to simply protect the cities against the incoming meteors for as long as possible. One interesting aspect of the game is that you lose points whenever you fire a missile, which makes it important to be efficient when you fire on the meteors. In other words, if you unleash missiles indiscriminately, you will no doubt protect the cities but your score will suffer. This is a subtle way to discourage sloppy game play. Small touches like this can often make a game much more appealing to serious game players. Designing the Game The design of the Meteor Defense game flows directly from the overview of the game that you just went through. The game is well suited for the starry background that you created and used in previous hours. It’s also fairly obvious that the meteors should be represented by animated sprites similar to those found in the Roids program example from the previous hour. Because you must be able to detect a collision between a meteor and a city, the cities also need to be modeled as sprites even though they don’t move. Representing cities as sprites also gives you the freedom to hide them whenever they are destroyed by a meteor. In case you were wondering, the terms meteor, meteorite, and meteoroid are all closely related. A meteoroid is a chunk of rock in space that ranges in size from a speck of dust to 100 meters across. A meteor is the bright flash of light generated by a meteoroid when it travels through Earth’s atmosphere. And finally, a meteorite is a meteor that has survived the transition through Earth’s atmosphere and comes to rest on the Earth’s surface. The missiles in the game are ideal candidates for sprites because they move and collide with meteors. This is generally a good rule of thumb when it comes to deciding which graphical objects should be represented as sprites and which ones can simply be placed in the background: If the object needs to move, animate, or collide with other objects, it should be a sprite. A good application of this test is the guns used to fire missiles in the Meteor Defense game. The guns don’t move, they don’t animate, and it isn’t important to detect a collision between them and anything else. Therefore, you can simply include the guns in the background image for the game. Wait a minute, I just mentioned using a background image, but I already said that the background is the starry background from earlier in the book. The Meteor Defense game actually uses a hybrid background in that it displays an image of the ground over the starry background. This allows you to get the benefits of the animated starry sky while also showing the ground where the cities are located not to mention the guns that fire the missiles. To help you get a feel for how the Meteor Defense game is laid out, take a look at Figure 19.1. Figure 19.1. The Meteor Defense game consists of a starry background, a ground image with guns, several cities, incoming meteors, and missiles. The figure reveals how the guns are part of the background image that appears along the bottom edge of the game screen. Keep in mind that a starry background still appears in the majority of the screen the background image just shows the ground where the cities are located. The city sprites are laid on top of the edge of the ground so that they blend into
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Clan Web Hosting services
Testing the Finished Product Granted, the Roids program example isn’t quite up to par with the classic Asteroids game. In fact, Roids isn’t a game at all. The reason for this is because I wanted to focus on the specific task of using an animated background without the distraction of trying to assemble a complete game. If you’re dying to build another complete game, your wishes will be answered in the next hour. But for now, take a look at Figure 18.2 to see the Roids program in action. Figure 18.2. The asteroid sprites in the Roids program tumble over an animated starry background thanks to the new background classes in the game engine. In addition to noticing how effective the twinkling stars are at presenting an interesting space background, hopefully you’re now appreciating the power of animated sprites. This has to do with the fact that the animated asteroids in the Roids program are considerably smoother and more detailed than the animated guys in the Battle Office 2 game where you first learned about animated sprites. It’s starting to become clear that you can get some surprisingly powerful visual effects out of the game engine when you combine an animated background with high quality sprite graphics. Summary Although you’ve certainly included backgrounds in several of the program examples and games that you’ve developed throughout the book thus far, this hour took a closer look at the role of backgrounds and why they are so important to games. You also found out about the main types of backgrounds, and what kinds of games demand each of them. The remainder of the hour focused on adding background support to the game engine in the form of two new classes, Background and StarryBackground. You now have a few classes you can reuse in your own games, as well as the knowledge to create custom animated backgrounds of your own. The next hour accumulates much of what you’ve learned throughout the book in an example game called Meteor Defense. If you’re familiar at all with the classic Missile Command game, you’ll no doubt appreciate the Meteor Defense game. Q&A Q1: How does the twinkle delay in the Roids example cause the twinkling of the stars to take place at different speeds? A1: The twinkle delay isn’t a delay in a sense that it establishes a counter that counts down at a constant rate. Instead, the twinkle delay alters the probability that a star’s color will be randomly changed. As an example, a twinkle rate of 1 means that a star’s color will change every game cycle. Increasing the twinkle delay lessens the odds that a star’s color will be changed. More specifically, a twinkle delay of 20 means that a star’s color will only change an average of 1 in every 20 game cycles. Similarly, the default value of 50 for the twinkle delay in the StarryBackground class means that the color of a star is changed once in every 50 game cycles. However, because there are 100 stars in the Roids program, an average of two stars are being changed in every game cycle, which still results in a fair amount of twinkling when you consider that there are 30 game cycles per second. Q2: How do I create my own custom animated backgrounds? A2: The best way to create your own custom backgrounds is to model them after the StarryBackground class. Just copy the source code files for the StarryBackground class, and modify them to accommodate the needs of your specific background. Keep in mind that the Update() and Draw() methods are the two primary interfaces used to interact with the background from the perspective of a game. So, you’ll want to make sure that all your
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost PHP Web Hosting services
animation code takes place in the Update() method and that the background is sufficiently painted in the Draw() method. Beyond that, it’s pretty much anything goes when it comes to creating your own custom animated backgrounds! Workshop The Workshop is designed to help you anticipate possible questions, review what you’ve learned, and begin learning how to put your knowledge into practice. The answers to the quiz can be found in Appendix A, “Quiz Answers.” Quiz 1: What are the four main types of backgrounds used in games? 2: Why is the Update() method in the Background class empty? 3: How many stars is the StarryBackground class capable of showing? Exercises 1. Change the number of stars in the Roids program example to see how they impact the appearance of the starry background. 2. Try a few different values for the twinkle delay in the Roids program example to see how they change the twinkling of the stars. You might decide that a different delay looks more realistic to you. Hour 19. Example Game: Meteor Defense This hour guides you through the design and development of another complete game. You’ve spent the past couple of hours learning how to animate the appearance of sprites and spruce up the background of games, and it’s now time to put this knowledge to work in an entirely new game. The game is called Meteor Defense, and it is loosely based on the classic Missile Command arcade game. Seeing as how there have been several news reports in the past few years about the potential of a significant meteor collision with the Earth, I thought it might make a neat premise for a game. It wouldn’t necessarily be a bad idea to have a missile-based system for stopping incoming meteors, which is the premise behind the game Meteor Defense. In this hour, you’ll learn: About the conceptual overview of the Meteor Defense game How to design the Meteor Defense game How to add a few new sprite features to the game engine What it takes to build the Meteor Defense game How much fun it can be testing a new game How Does the Game Play? One of the classic arcade games that many people remember is Missile Command, which involves the defense of a group of cities against a nuclear attack. The nuclear attack involves missiles that travel down from the top of the screen toward the cities at the
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost PHP Web Hosting services
1: #pragma once 2: 3: //—————————————————————-4: // Include Files 5: //—————————————————————-6: #include 7: #include “Resource.h” 8: #include “GameEngine.h” 9: #include “Bitmap.h” 10: #include “Sprite.h” 11: #include “Background.h” 12: 13: //—————————————————————-14: // Global Variables 15: //—————————————————————-16: HINSTANCE _hInstance; 17: GameEngine* _pGame; 18: HDC _hOffscreenDC; 19: HBITMAP _hOffscreenBitmap; 20: Bitmap* _pAsteroidBitmap; 21: StarryBackground* _pBackground; The first variable unique to the Roids program is _pAsteroidBitmap (line 20), which is a bitmap for an asteroid image. This image is actually a series of frame images for an asteroid that appears to be tumbling when it is animated. A total of 14 frames are in the asteroid image, as you find out in a moment when you create the asteroid sprites. The other important global variable in the Roids program is the _pBackground variable, which stores a pointer to a StarryBackground object (line 21). This object serves as the background for the program, as you soon find out. The GameStart() function is where the Roids program really gets rolling because it is responsible for creating bitmaps and sprites, not to mention the starry background. Listing 18.8 shows the code for this function. Listing 18.8 The GameStart() Function Creates and Loads the Asteroid Bitmap, the Starry Background, and the Asteroid Sprites 1: void GameStart(HWND hWindow) 2: { 3: // Seed the random number generator 4: srand(GetTickCount()); 5: 6: // Create the offscreen device context and bitmap 7: _hOffscreenDC = CreateCompatibleDC(GetDC(hWindow)); 8: _hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow), 9: _pGame->GetWidth(), _pGame->GetHeight()); 10: SelectObject(_hOffscreenDC, _hOffscreenBitmap); 11: 12: // Create and load the asteroid bitmap 13: HDC hDC = GetDC(hWindow); 14: _pAsteroidBitmap = new Bitmap(hDC, IDB_ASTEROID, _hInstance); 15: 16: // Create the starry background 17: _pBackground = new StarryBackground(500, 400); 18: 19: // Create the asteroid sprites 20: RECT rcBounds = { 0, 0, 500, 400 }; 21: Sprite* pSprite; 22: pSprite = new Sprite(_pAsteroidBitmap, rcBounds, BA_WRAP); 23: pSprite->SetNumFrames(14); 24: pSprite->SetFrameDelay(1); 25: pSprite->SetPosition(250, 200); 26: pSprite->SetVelocity(-3, 1); 27: _pGame->AddSprite(pSprite); 28: pSprite = new Sprite(_pAsteroidBitmap, rcBounds, BA_WRAP); 29: pSprite->SetNumFrames(14); 30: pSprite->SetFrameDelay(2); 31: pSprite->SetPosition(250, 200); 32: pSprite->SetVelocity(3, -2); 33: _pGame->AddSprite(pSprite);
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Cheap Web Hosting services
34: pSprite = new Sprite(_pAsteroidBitmap, rcBounds, BA_WRAP); 35: pSprite->SetNumFrames(14); 36: pSprite->SetFrameDelay(3); 37: pSprite->SetPosition(250, 200); 38: pSprite->SetVelocity(-2, -4); 39: _pGame->AddSprite(pSprite); 40: } The first few sections of code in the GameStart() function should be familiar to you from other program examples, so I’ll spare you a recap. Instead, let’s jump straight to the line of code that creates the StarryBackground object (line 17). As you can see, the starry background is set to a size of 500 by 400, which is the same size of the game screen. Because no other arguments are provided to the new object, the default values of 100 for the number of stars and 50 for the twinkle delay are assumed. The remainder of the GameStart() function focuses on the creation of the asteroid sprites. Notice that the number of frames for each of these sprites is set to 14 (lines 23, 39, and 35), which indicates that 14 frame images are stored in the image for the asteroid. Also, the frame delay of each sprite is set differently so that the asteroids appear to tumble at different speeds (lines 24, 30, and 36). Beyond those settings, nothing is tricky or otherwise noteworthy regarding the asteroid sprites. The GamePaint() function is responsible for drawing the graphics in the Roids program, as shown in Listing 18.9. Listing 18.9 The GamePaint() Function Draws the Starry Background and the Asteroid Sprites 1: void GamePaint(HDC hDC) 2: { 3: // Draw the background 4: _pBackground->Draw(hDC); 5: 6: // Draw the sprites 7: _pGame->DrawSprites(hDC); 8: } The important line of code worth paying attention to here is the line that calls the Draw() method on the StarryBackground object (line 4). As long as the background is drawn before the sprites, everything works great. The final function on the Roids agenda is GameCycle(), which takes care of updating the animated graphics in the program. Because the background is animated, it too must be updated in GameCycle() function, as shown in Listing 18.10. Listing 18.10 The GameCycle() Function Updates the Starry Background and Asteroid Sprites, and then Repaints the Game Screen 1: void GameCycle() 2: { 3: // Update the background 4: _pBackground->Update(); 5: 6: // Update the sprites 7: _pGame->UpdateSprites(); 8: 9: // Obtain a device context for repainting the game 10: HWND hWindow = _pGame->GetWindow(); 11: HDC hDC = GetDC(hWindow); 12: 13: // Paint the game to the offscreen device context 14: GamePaint(_hOffscreenDC); 15: 16: // Blit the offscreen bitmap to the game screen 17: BitBlt(hDC, 0, 0, _pGame->GetWidth(), _pGame->GetHeight(), 18: _hOffscreenDC, 0, 0, SRCCOPY); 19: 20: // Cleanup 21: ReleaseDC(hWindow, hDC); 22: } The background is the first thing updated in the GameCycle() function (line 4), and this simply involves a call to the Update() method on the StarryBackground class. This call is sufficient enough to cause the entire background to come alive with twinkling stars. If you don’t believe me, try commenting out this line of code and see what happens to the background no animation, and therefore not much excitement!
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Cheap Web Hosting services