Handling Game Level Updates
Handling Level UpdatesWhat about the level itself? Currently there is no way to render the level, so you should add that now. Add the code from Listing 8.6. Listing 8.6. Rendering the Levelpublic void Draw(Device device) { // Render every block for each(Block b in blocks) { // It's possible the block may be null if (b != null) { b.Draw(device); } } } Wow, that's probably the easiest render method yet. You simply loop through every block in the level and, assuming it isn't null, call the Draw method on it. Because the work for rendering the blocks is encapsulated in the Block class, it makes the rendering of the entire level extremely simple. You're still currently missing one important method that the other classes had, namely a way to update the level state every frame. Add the Update method in Listing 8.7 to your class. Listing 8.7. Updating Level Each Framepublic void Update(float time) { // Update the currently running time elapsedTime += time; // Calculate the time remaining if (maxTime > elapsedTime) { timeLeft = new TimeSpan(0,0, (int)(maxTime - elapsedTime)); } // Has the player won the game? if (GameWon(elapsedTime)) { // Set the variables and return isGameOver = true; isGameWon = true; } else if ((elapsedTime >= maxTime) || (totalMoves > maxMoves)) { // Set the variables and quit isGameOver = true; isGameWon = false; } // Update the blocks if the game is over if ((isGameOver) && (!isGameWon)) { // If this is the first time the game is over, // randomly assign a velocity to each block if (isFirstGameOver) { isFirstGameOver = false; Random r = new Random(); int index = 0; foreach(Block b in blocks) { if ((b != null) && (playerIndex != index)) { // Assign a random velocity float x, y, z = 0.0f; x = (float)r.NextDouble() * Block.MaximumVelocity; y = (float)r.NextDouble() * (Block.MaximumVelocity * 2); z = (float)r.NextDouble() * Block.MaximumVelocity; if (r.Next(50) > 25) { x *= -1; } if (r.Next(50) > 25) { y *= -1; } if (r.Next(50) > 25) { z *= -1; } b.SetBlockVelocity(new Vector3(x, y, z)); } index++; } } foreach(Block b in blocks) { if (b != null) { b.UpdateBlock(time); } } } } The time parameter passed into this method is the time that has passed since the last frame was rendered or, more specifically, the time that has elapsed since the last call to this method. The current total elapsed time is incremented by this time, and the time remaining to solve the level is calculated (assuming you haven't already run out of time). Obviously, you should check whether the game is won before you check whether the player has lost. (You always want to give the player the benefit of the doubt.) The implementation of this method will be coming in just a few moments. If the player hasn't won the game yet, you should check whether she's lost the game. The game is lost if the elapsed time exceeds the maximum time for the level or if the total number of moves exceeds the maximum number for the level. The next portion of code causes the blocks to explode off the screen in a nifty effect if the level is lost. First, you need to see whether this is the first time you've made it into this loop, and if it is, you randomly assign a velocity to each block with the exception of the one the player is currently on. After you set the velocity on the blocks, each subsequent call simply calls the UpdateBlock method to move the blocks based on the current velocity. Listing 8.8. Checking Whether the Game Is Wonprivate bool GameWon(float totalTime) { bool won = true; numberBlocks = 0; numberCorrectBlocks = 0; // Just scroll through each block and see if it is the correct color for each(Block b in blocks) { // Is there a block here? if (b != null) { numberBlocks++; b.SetBlockTime(totalTime); // Is it the right color? if (b.BlockColor != finalColor) { // Nope, you haven't won yet. b.SetBlockPulse(true); won = false; } else { b.SetBlockPulse(false); numberCorrectBlocks++; } } } return won; } The time is passed into this method because while this code scans through the blocks, the time is updated to allow the pulsating code to work correctly. Each time this method is called (which is every frame), the number of blocks and the number of correct blocks are both reset to zero, the method assumes the game is won, and then each block in the level is examined. If there is a block in any given position, the number of blocks is incremented and the time set. If the color of the block is correct (meaning it is equal to the final color), the pulse of the block is turned off, and the number of correct blocks is incremented. If the block isn't the correct color, the pulse is turned on, and the won variable is set to false to signify that the level hasn't been won yet. After each block is examined, the method returns either true if the level has been won or false otherwise and leaves the number of blocks and the number of correct blocks' variables set correctly. The last thing that you need to add to your Level class is public accessibility for the members which the game engine will need to use. Add the properties in Listing 8.9 to the class to facilitate this. Listing 8.9. Public Properties/// |
Comments