Exercise 3.1: Testing the Pop programAny large program's code is likely to have bugs in it, and it's even more likely that there are places where the documentation is out of sync with the actual behavior of the program. While going through the help file and testing the Pop program, look for these three kinds of problems. Bugs . A bug is when the program does something that seems wrong. Crashing is the extreme case, but other kinds of odd behavior can be bugs as well. For a useful bug report, explain exactly how to reproduce the bug. Note that it possible that something the tester thinks of as a bug may be what the programmer thinks of as a feature. Bad features . Features of the program that you find bad or confusing or which look like bugs. Explain what you don't like. If many testers have the impression that a feature is a bug, then the feature needs be changed or, at the very least, better documented. Bad documentation . Find cases where the help file description does not seem to match the behavior of the program. Also note cases where some program feature is not well-explained. Exercise 3.2: First buildInstall Visual Studio. Put the Pop code onto your hard drive, find the pop.sln file (Version 7.0) [or pop.dsw file (Version 6.0)] file in the Windows Explorer and double-click on it to open up the project in Visual Studio. Press Ctrl+Shift+B (Version 7.0) [or F7 (Version 6.0)] to build the Pop program, watching the messages that go by in the Output pane that can be found at the bottom of the Visual Studio window. If you get a successful build, press F5 to run the Pop program inside the Visual Studio debugger. If you have any problems or questions check Chapter 20: Using Microsoft Visual Studio for more information. After the build, use Windows Explorer to see what kinds of files have been added to your disk by the build. Exercise 3.3: Code hand-offFirst clean your Pop code directory by closing Visual Studio, using Windows Explorer to navigate into the directory, and clicking on clean.bat . After clean.bat runs, use Windows Explorer to see if there are any *.exe still in the directory. If there are, delete them so as to minimize your directory size. If you don't have WinZip on your machine, go to www.winzip.com and download and install a free evaluation copy. Choose the 'Classic' settings as your preferred WinZip default. Right-click on your Pop code directory and select WinZip from the context menu to zip it up. Note these considerations about the WinZip settings. Let's assume you are running WinZip in the 'Classic' interface mode and that you are using the current (as of Spring, 2002) Version 8.1. WinZip will save your directory name, which is good, as the directory name will probably have version and date information. Also WinZip automatically saves your directories subdirectories, which is good, as you need the res subdirectory to be able to rebuild the code. In the Options field of the Add dialog box, don't check Save Extra Folder Info . You don't want to check Save Extra Folder Info because, for portability, you don't want to include the full path to directory where your files live. Even if this isn't checked, WinZip will save the name of the directory you are zipping. Choose the name mypop1.zip for your zip file and save it somewhere where you can find it, perhaps in the C:\Temp directory. Don't save it in with the same code that you're zipping. After its been zipped , find mypop1.zip and unzip it (not into the same location as the original Pop code that you were working with). Open its pop.dsw with Visual Studio and see if it will build. If this works, try sending mypop1.zip to yourself as an email attachment, see if you can then unzip it and build it. Practice these steps until you can do them all. Exercise 3.4: Changing the date information for your buildSet the date of your Pop build to match the current date in three places. (a) Put a version number and a build date into the name of your executable file. In Visual Studio, Version 7.0, first make sure that you have View Project Explorer open and that you have clicked on the Pop node, and then use View Property Pages Linker General Output File . If another node is active, Property Pages will open up a different dialog. [In Version 6.0, you can always simply use the Program Settings Link General Output File Name .] Change the name of the executable both for the Release build and the Debug build. You switch between them in either Version 6.0 or 7.0 by using the settings for control in the upper left-hand corner of the dialog box with which you are editing the output file name. (b) Open the Resource view. You can do this in Version 7.0 with View Resource View . [In Version 6.0, use View Workspace Res , where you'll find the 'Res' as a tab at the bottom of the Workspace window.] Click on the String Table resource in Resource View and then click on IDR_MAINFRAME to use this string to include the build number and the date; this string is what appears in the caption bar of your *.exe. (c) Change the name of the directory where you code lives by highlighting the the directory name in Explorer and pressing F2 so you can edit it. Exercise 3.5: Look at some Pop code filesWith the Pop project in Visual Studio, use File Open to open the gamespacewar.h and gamespacewar.cpp files to get an idea of how much code goes into a game definition. You'll see that it's not all that much, as you only need to mention the methods that you plan to override. Now look at the game.h and game.cpp files to get an idea of what kinds of methods cGameSpacewar inherits from cGame . Now take a brief look at the critter.* and critterarmed.* files. This code is fairly gnarly (in the sense of 'complex'), but we'll explain a lot of it later on. For now just scan over critter.h to get an idea of what the cCritter methods are. Exercise 3.6: Look at the Pop resourcesOpen the Pop project in Visual Studio and then open the Resource View. You can do this in Version 7.0 with View Resource View . [In Version 6.0, use View Workspace Res , where you'll find the 'Res' as a tab at the bottom of the Workspace window.] Now click on the various items in the Resource view to view them “ the way this works is that anything with a + next to it is like a directory to be opened up. Click down through the things with + till you get some bottom level things like bitmaps, menus , etc. Find the IDB_BACKGROUND bitmap and the IDR_POPTYPE menu. Note that the Resource view of the menu is 'live,' that is, you can open up the menu selections and edit them. This is useful as, later, when you want to turn Pop into a single game, you can simply remove the menu references to the other game modes so that the users won't have the possibility of going into them. Exercise 3.7: Renaming a gameChanging the names of a game that appear in copies of existing files is a little tricky. In this problem we ask you to practice. In Windows Explorer, select the gamestub *. h and *. cpp files, and use Ctrl+C and Ctrl+V to copy them. Highlight the file names one by one, press F2 and change the names to, say, gamemyproject.h and gamemyproject.cpp . Now open up the Pop Framework in Visual Studio and use the Project Add Existing Item... dialog (Version 7.0) [or Project Add to Project Files... dialog (Version 6.0)] dialog to add your new files to the project. Edit the files in Visual Studio to replace every instance of the phrase 'Stub' by the phrase 'MyProject,' being sensitive to upper and lower case. That is, you must replace 'Stub' by 'MyProject', 'stub' by 'myproject' and 'STUB' by 'MYPROJECT'. You can do this by using Ctrl+H to do a search and replace several times in each file, with the Match Case checkbox turned on. Now see if you can get the altered project to compile. This may take a couple of tries , especially if you weren't careful about case sensitivity in the search and replaces . If you've totally messed things up (always easy to do when starting out!) make fresh copies of the files and start over. Once it compiles, edit the CPopDoc constructor in the popdoc.cpp file so that the default start up game class is cGameMyProject . You'll have to add a line #include "gamemyproject.h" to popdoc.cpp so this will compile. If you want to do a bit more, look at Chapter 27: Menus and Toolbars and figure out how to add and implement a My Project option on the Game menu. Exercise 3.8: Expanding a UML diagramThe UML diagram given for the cGameStub in this chapter is missing the classes cCritterArmedPlayer , cCritterArmedRobot , and cCritterBulletSilver . Redraw the picture, with these intermediate classes squeezed into the tree of inheritance. Exercise 3.9: Writing a Space Invaders gameThe rest of the problems on this chapter have to do with converting the Game Stub game into a Space Invaders game. Game stub modified to resemble a Space Invaders game
Rather than carrying out the slightly tricky task of changing all the names in the gamestub .* files, let's just use these files as is, and make some changes in them. You might want to save off reference copies of these files called gamestubold .* in case you want to get the old code back after a while. Or simply make sure that you do your work in a fresh copy of the whole Pop source directory. The following exercises describe a specific series of changes to make to the files. The purpose is simply to have you get a feel for how you might make your own game out of the Pop code. Don't feel you need to be able to understand all of the code you see, just go ahead and carry out the following steps to see how you might work with it. Just in case you've never seen a Space Invaders game, the idea is that the player controls an upwards-pointing critter that can be moved left and right along the bottom of the screen with the arrow keys. The critter shoots a bullet upwards when the spacebar is pressed. Falling down from the top of the screen are enemy critters. Shooting enemies gives the player score points, and each time an enemy survives to touch the bottom of the screen, the player loses a health point. Whenever all the falling creatures have been shot, a new wave of them appears; alternately we can bring in new enemies as fast we kill them off. Typically the player starts with three or maybe five health points and plays until he or she loses them all. The new waves of enemies move faster than the earlier waves, so that as time goes on, the game gets harder and harder to play, inevitably ending in the player's death. The score points accumulated are a measure of how long the player managed to stay alive . A Space Invaders style game is generally not considered to be an acceptable project for a course taught with the Software Engineering and Computer Games textbook . The reason is that (a) this project is too easy and (b) the one-dimensionality of the Space Invaders game player motion makes the game pretty boring. Once you finish the Space Invaders game in this section, you should set it aside and make a fresh start for your real course project. Exercise 3.10.1: Change the default game. Beware the wrong-directory-gotchaWhen you get into tweaking one particular game mode, it saves time to have the Pop program start up in the game mode that you want to play with. The way to control this is to edit the CPopDoc constructor in popdoc.cpp . Simply comment in exactly the one setGameClass line corresponding to the game you want to play. If you make a new game class, add a line for it. For the following exercises, have your startup game be cGameStub . CPopDoc::CPopDoc(): _pgame(NULL) { /* Choose the type of game you want at startup by commenting in ONE setGameClass line. The setGameClass sets brandnewgameflag to TRUE. */ // setGameClass(RUNTIME_CLASS(cGameSpacewar)); // setGameClass(RUNTIME_CLASS(cGameAirhockey)); // setGameClass(RUNTIME_CLASS(cGameBallworld)); // setGameClass(RUNTIME_CLASS(cGameDambuilder)); // setGameClass(RUNTIME_CLASS(cGamePickNPop)); // setGameClass(RUNTIME_CLASS(cGameWorms)); setGameClass(RUNTIME_CLASS(cGameStub)); // setGameClass(RUNTIME_CLASS(cGameStub3D)); // setGameClass(RUNTIME_CLASS(cGameDefender3D)); } If you do this exercise and the game still starts up in the original Spacewar Game mode, it's very likely that you edited the wrong copy of popdoc.cpp . One of the gotchas of Visual Studio is that when you use the File Open command, the file selection dialog doesn't make it clear which directory you are in. Visual Studio has a certain persistence of state, and if you open a file in DirectoryA, the next time you open a file the dialog is likely to search in DirectoryA again, even if you are now working on a project in DirectoryB. One often has multiple copies of the Pop Framework code on one's disk, and it is easy to be editing a file in the wrong directory. A sure sign that you're editing the wrong files is if (a) your program always compiles and runs with no warnings or error messages and (b) the appearance of the executable looks the same after each 'build.' How to avoid this gotcha? If you see signs of (a) and (b), close all your files, close your project, reopen your project in your desired directory, and then open your file, only this time use the File Open dialog to back a step or two up the directory tree to find out what directory you're really in, and then go back down into the correct directory. Exercise 3.10.2: Change the cGameStub worldWe edit some of the cGameStub methods in the gamestub.cpp file to change the appearance of the game world.
Exercise 3.10.3: Change the cCritterStubPlayer
Exercise 3.10.4: Change the cCritterStubProp constructorNow we make some changes to the bottom of the cCritterStubProp::cCritterStubProp(cGame *pownergame) code in gamestub.cpp.
Exercise 3.10.5: Change cCritterStubProp::updateEach critter has an int _outcode field that is an OR combination of bit flags telling you which, if any, edge of its cRealBox _movebox the critter touched during its last move. The bit flags, which are defined in the realbox.h file, have simple names like BOX_LOY . We will use the _outcode to take action when a cCritterStubProp hits the bottom or the top of the screen. When one of the cCritterStubProp critters hits the bottom of the screen, we want to kill off the critter and reduce the player's health by calling its damage method. If you have called setWrapflag(cCritter::WRAP) , then the cCritterStubProp might get to the bottom by going around the top. When our cCritterStubProp run away from bullets they might sometimes do this. It would unfairly punish the player if we let the cCritterStubProps get away with that, as then they would be in a position to cross back and the game might think they landed on the bottom. Therefore if a cCritterStubProp hits the top of the world we kill it off without charging the player a damage point. We do all this by changing the cCritterStubProp update method to look like this. void cCritterStubProp::update(CPopView *pactiveview, Realdt) { cCritter::update(pactiveview, dt); //Always call this first if (_outcode & BOX_LOY) //Landing damages me { pplayer()->damage(1); die(); } if (_outcode & BOX_HIY) //So they don't sneak around over the top. die(); } Exercise 3.10.6: Change cCritterStubPlayer::collideLet's eliminate the feature of cGameStub which rewards the player for bumping into a cCritterStubProp critter. This means you should comment out this line from within the lines from the cCritterStubPlayer::collide(cCritter *pcritter) code. // setHealth(health() + 1); Exercise 3.10.7: Change cCritterStubPlayer::shoot , and the cCritterStubPlayerBullet behavior
Exercise 3.10.8: Change the cGameStub::adjustGameParameters
Exercise 3.11: Hand in a Space Invaders projectThis is an assignment the author usually gives his classes fairly early in the semester. Typically, the credit assigned for the three parts of this problem is in a 25%, 50%, 25% ratio for, respectively, mechanics, basics and improvements. Even if you're studying this book on your own, you will find it worthwhile to carry through the mechanics steps so as to have experience in putting your code into a form that can be handed off. Mechanics . Hand in the following: (1) A sheet of paper with a little ' User 's Guide' describing the controls of your game and listing any special features you added. (2) Two floppy disks: one disk with a release build of the executable in the root directory, and another disk with clean, minimal- sized , buildable source code. Label the disks with your name and with a word to indicate if this is the EXE or the SOURCE disk. You will probably need to WinZip your source and probably your executable to fit onto floppies. If the *.zip is larger than 1 Meg you probably haven't cleaned your source directory properly (or you've included a lot of extra big sounds and bitmap files). Another option is to write the information onto a CD-ROM. Emailing your homework to the professor as a gigundo attachment is forbidden! (3) Put disks and paper in a two-pocket folder with your name on it. (4) Put your name on the program caption bar. To change the caption bar, see Section 23.9 of this book. Basics . Carry out the steps outlined in the series of Space Invaders exercises 3.10.1 “ 3.10.8 just above. You don't necessarily need to use all the exact same parameter values suggested. Get the program working so that the critters are neither too hard nor too easy to hit, the game itself should be neither too hard nor too easy. You may need to tweak some parameters to get it right. Improvements . Possibilities: change the background, use different kinds of sprites , add code to make the game use levels that get progressively harder, change the code so that the enemies jiggle back and forth like in the traditional Space Invaders rather than running away from bullets. Add sound effects. Have some enemies that shoot at you. Have the enemies change appearance when you hit them before disappearing , maybe have them shatter or show a cSpriteIcon or cSpriteLoop explosion bitmap for a few seconds. Looking at the gamespacewar.cpp or the gamedefender3d.cpp files may provide inspiration. |