Hooking Up the Level


The rest of the interaction with the player has already been implemented inside the code for the Level object, so for now you are done with this object. However, you do need to add the level into the game engine. Go ahead and declare some variables for it:

 // The current level private Level currentLevel = null; // What level are we currently playing private int levelNumber = 1; // Is the level currently being loaded private bool isLoadingLevel = false; // Current camera position private Vector3 currentCameraPosition; // The amount of time the 'winning' screen is displayed private float winningLevelTime = 0.0f; 

The first two variables are pretty obvious: you need to know which level number you're currently playing as well as the level object itself. You also want to do a quick "flyby" of the level before you actually allow the player to start playing, which is controlled by the Boolean variable and the current camera position. Finally, after a level is finished, you want a message notifying the player to show onscreen for some period of time.

You should create the initial level at the same time you create the player object, directly after the character selection screen. So at the end of the CreateGraphicsObjects method, add a call to the method that will control the creation of the level:

 // Load the current level LoadCurrentLevel(); 

You can find the implementation of this method in Listing 9.5.

Listing 9.5. Loading the Current Level
 private void LoadCurrentLevel() {     // Load our level     currentLevel = new Level(levelNumber, device, player);     // Create a random camera location     CreateRandomCamera();     // Now we're loading the level     isLoadingLevel = true;     winningLevelTime = 0.0f; } 

As the name implies, the CreateRandomCamera method creates a random starting location of the camera, which then "flies" into position. You set the loading level variable to TRue, so later you'll know if the user can play the level yet. Because you obviously don't win the level when it is first loaded, you can reset the time here as well. You'll find the implementation for the camera method in Listing 9.6.

Listing 9.6. Creating a Random Camera Location
 private void CreateRandomCamera() {     Random r = new Random();     currentCameraPosition = new Vector3(         (float)r.NextDouble() * 5.0f + 15.0f,         (float)r.NextDouble() * 10.0f + 120.0f,         (float)r.NextDouble() * 5.0f + 15.0f         );     // Randomly switch     if (r.Next(100) > 49)     {         currentCameraPosition.X *= -1;     }     // Randomly switch     if (r.Next(100) > 49)     {         currentCameraPosition.Z *= -1;     } } 

There's nothing unusual going on in this method. You use the random number generator to generate a random location, always very high above the level. Because the random number generator only returns positive numbers, the X and Z axes are also randomly changed to negative.

As with the player, you also need to ensure that the level and now the camera are updated every frame. You can finish up the OnFrameMove method by including the code in Listing 9.7 at the end of the method.

Listing 9.7. Updating the Level and Camera
 // Make sure the level isn't started until the camera moves to position UpdateCamera(elapsedTime); // See if we need to keep showing the 'you win' screen if ((currentLevel.IsGameWon) && (winningLevelTime > ShowWinningTime)) {     // Make sure the new level exists     if (Level.DoesLevelExist(levelNumber + 1))     {         // Reset the variables         levelNumber++;         LoadCurrentLevel();     } } // If the level is won, then increment our timing for showing the screen if (currentLevel.IsGameWon) {     winningLevelTime += elapsedTime; } // Update the current level if (!isLoadingLevel) {     currentLevel.Update(elapsedTime); } 

The UpdateCamera method is used to fly the camera into position (if it isn't already there), and you need to implement this method. Skipping that for a moment, what else happens here? For one, you can detect whether the level has been won and, if it has, whether the winning message has been shown for long enough. You need to declare the constant used here as well:

 private const float ShowWinningTime = 2.5f; 

This value shows the winning message for two and a half seconds; feel free to adjust it to suit your needs. Assuming the level has been won for more than two and a half seconds, you can then check whether the next level exists and, if it does, increment the level counter and load the new level. This part resets all the game states and the winning time.

Otherwise, the only thing you want to do is update the winning time variable if the level has been won and call the Update method on your level object, which updates all the states in the level. You still need to implement the camera method, however, and you find that in Listing 9.8.

Listing 9.8. Implementing a Camera Flyby
 private void UpdateCamera(float elapsedTime) {     if (currentCameraPosition != CameraDefaultLocation)     {         Vector3 diff = CameraDefaultLocation - currentCameraPosition;         // Are we close enough to just move there?         if (diff.Length() > (MaximumSpeed * elapsedTime))         {             // No we're not, move slowly there             diff.Normalize();             diff.Scale(MaximumSpeed * elapsedTime);             currentCameraPosition += diff;         }         else         {             // Indeed we are, just move there             currentCameraPosition = CameraDefaultLocation;         }         // Set the view transform now         device.Transform.View = Matrix.LookAtLH(currentCameraPosition,             CameraDefaultLookAtLocation, CameraUp);     }     else     {         isLoadingLevel = false;     } } 

First, you notice a few constants that haven't been declared yet, so you want to do that now:

 // Camera constants private const float MaximumSpeed = 30.0f; private static readonly Vector3 CameraDefaultLocation = new Vector3(     -2.5f, 25.0f, -55.0f); private static readonly Vector3 CameraDefaultLookAtLocation = new Vector3(     -2.5f, 0.0f, 0.0f); private static readonly Vector3 CameraUp = new Vector3(0,1,0); 

These constants define where the camera's final destination should be, as well as where the camera will be looking, and the up direction of the camera. (The latter two won't change.) The movement code is similar to what was used to move the player into the correct position. If the camera is not already in the correct position, it is moved directly into position (if is close enough to move there this frame). If it isn't close enough to move there directly, the camera is moved toward the final location at a rate of 30 units per second. After the camera is in place, the isLoadingLevel variable is set to false, and the game play can begin.

Notice that if the camera's position changes, the View transform on the device is updated as well. You originally set this transform in the OnResetDevice method with some default values. Because the camera can be moving when the device is reset, you want to update the camera back to the correct position, not the default values you have there now. Replace the setting of the View transform in the OnResetDevice method with the following:

 // Set the view transform now device.Transform.View = Matrix.LookAtLH(currentCameraPosition,     CameraDefaultLookAtLocation, CameraUp); 

As you see, this is the same transform you set in the UpdateCamera method; it's now used when the device is reset as well. You've almost got everything implemented, but before you finish the rest of the game engine, there's one important thing to take care of.



Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net