.Netterpillars: Artificial Intelligence and Sprites, Part 2 - The Main Program: Final Version
(Page 10 of 11 )
In order to call the AI code, you create a new procedure, which will be called from the game main loop. The procedure, shown in the following code, just loops through the Netterpillars objects and, if they aren’t dead and are computer controlled, sets the current direction to the result of the ChooseNetterpillarDirection method:
public static void MoveComputerCharacters() {
//Move the Netterpillars.
for(int i=0; i<objGameEngine.NetterpillarNumber; i++) {
if (!objGameEngine.netterPillars[i].IsDead) {
// A.I. for the computer-controled Netterpillars.
if (objGameEngine.netterPillars[i].IsComputer) {
objGameEngine.netterPillars[i].Direction =
objAINetterpillar.ChooseNetterpillarDirection
(objGameEngine.netterPillars[i].Location,
objGameEngine.netterPillars[i].Direction);
}
}
}
}
The main program loop should include one more section to call the MoveComputerCharacters procedure.
while ( !objGameEngine.GameOver) {
MoveComputerCharacters();
objGameEngine.Render();
Application.DoEvents();
}
This finishes the coding phase; some code to add polish to the final product is suggested in the next section.
Adding the Final Touches In this section, you add some extra features to your game. These final touches, although simple, are important and need to be considered.
Coding the Pause Game Feature As in the .Nettrix game, you could insert code to pause (and restart) the game when the Esc key is pressed. This basic improvement is shown here:
private void frmGameField_KeyDown(object sender,
KeyEventArgs e) {
…
case Keys.Escape:
MainGame.objGameEngine.Paused = !
MainGame.objGameEngine.Paused;
if (MainGame.objGameEngine.Paused) {
this.Text = “.Netterpillars - Press ESC to
continue”;
}
else {
this.Text = “.Netterpillars”;
}
break;
}
}
Improving the Game Over Screen Your game over routine also needs an improvement. A good game programmer shouldn’t forget that a good game ending is far more important than a nice intro screen. Players must be rewarded for all their efforts in completing the game; it’s very frustrating for players to spend days and days finishing a game and not getting anything in return to give them a feeling of accomplishment. In this game, the Game Over message box is one of these frustrations. Although a high scores table would be better, let’s at least give players some feedback about the results of the game and how well they played.
You can do this by creating a new Game Over window, where you can display some game statistics, as shown in Figure 2-18.

Figure 2-18. A Game Over screen
This screen can access the objGameEngine, which is a public variable, and gather information about players and how long their netterpillars were when the game finished.
To load the label with the statistics, you must access each of the netterPillars objects, checking the IsComputer property and the NetterBodyLength property. You’ll need to avoid unset objects (remember, the player could be playing with any number of opponents, from 0 to 3).
The ternary operators in the next code sample (which must be placed in the Load event of the window) aren’t new to .NET, although they aren’t commonly used because sometimes they can lead to more complex code. The ternary operator tests the first parameter (an expression) and, if true, returns the second parameter; otherwise it returns the last parameter.
LblPlayer1Length.Text =
MainGame.objGameEngine.netterPillars[0]
.NetterBodyLength.ToString();
LblPlayer1Is.Text = MainGame.objGameEngine.netterPillars[0]
.IsComputer ? “Computer” : “Human”;
if (MainGame.objGameEngine.netterPillars[1]!=null) {
LblPlayer2Length.Text =
MainGame.objGameEngine.netterPillars[1]
.NetterBodyLength.ToString();
LblPlayer2Is.Text =
MainGame.objGameEngine.netterPillars[1].IsComputer
? “Computer” : “Human”;
}
else {
LblPlayer2Length.Text = “-”;
LblPlayer2Is.Text = “-”;
}
if (MainGame.objGameEngine.netterPillars[2]!=null) {
LblPlayer3Length.Text =
MainGame.objGameEngine.netterPillars[2]
.NetterBodyLength.ToString();
LblPlayer3Is.Text =
MainGame.objGameEngine.netterPillars[2].IsComputer
? “Computer” : “Human”;
}
else {
LblPlayer3Length.Text = “-”;
LblPlayer3Is.Text = “-”;
}
if (MainGame.objGameEngine.netterPillars[3]!=null) {
LblPlayer4Length.Text =
MainGame.objGameEngine.netterPillars[3]
.NetterBodyLength.ToString();
LblPlayer4Is.Text =
MainGame.objGameEngine.netterPillars[3].IsComputer
? “Computer” : “Human”;
}
else {
LblPlayer4Length.Text = “-”;
LblPlayer4Is.Text = “-”;
}
In final version of the main program, you must replace the Game Over message box by a call to the ShowDialog method of the game over form.
Coding for the Garbage Collection A technical enhancement is to improve the speed of the garbage collection by calling the Collect method of the System.GC object, in the end of the Render method, as shown:
public void Render() {
…
System.GC.Collect();
}
NOTE The .NET Framework provides an advanced garbage collector that frees the memory from all objects left behind by the program. The garbage collection takes place in idle system time, but you can force it to run by calling the Collect method, which is good practice if you are dealing with lots of memory allocations and reallocations—which you do, for example, with the Graphics object in each Draw method in the game objects.
This chapter is from Beginning .NET Game Programming in C# by Ellen Hatton et al. (Apress, 2004, ISBN: 1590593197). Check it out at your favorite bookstore today. Buy this book now.
|
Next: Further Improvements >>
More ASP.NET Articles
More By Apress Publishing