Putting It All Together


You saw some bits and pieces of XNA Shooter in the previous two chapters. Before you can start you need all files in the XNA Shooter project, which has to be created first. The project needs all the sound effects together with the XACT project, and all the usual files like shaders, standard textures for fonts, testing, the menu, and so on. Finally, after adding the .x files for the 3D models and their textures you can go ahead and test them out with help of the unit tests you have in the Texture, Shader, and Model classes.

Figure 11-1 shows the new project, which is just called XnaShooter, after performing the following actions:

  • Creating a new Windows XNA Game project in XNA Game Studio Express with the name “XnaShooter.”

  • Dragging in all source code files from the Rocket Commander XNA project, which was based on the XnaGraphicEngine. The following files were removed because you won’t need them in XnaShooter, sorted by namespaces:

    • Game namespace: Asteroid.cs, BaseAsteroidManager.cs, GameAsteroidManager.cs, Level.cs, PhysicsAsteroidManager.cs, SmallAsteroid.cs, and SpaceCamera.cs

    • GameScreens namespace: Help.cs, MissionSelection.cs, and Options.cs

    • Graphics namespace: AnimatedModel.cs and LensFlare.cs

    • Shaders namespace: ParallaxShader.cs and PreScreenSkyCubeMapping.cs

  • Game1.cs was also removed and the RocketCommanderGame class was renamed to XnaShooterGame.

  • The RocketCommanderXna namespace that is used in all files is replaced with the XnaShooter namespace.

  • Most code from the Mission.cs, Player.cs, MainMenu.cs, and XnaShooterGame.cs had to be commented out in order to allow compiling the project.

image from book
Figure 11-1

Sounds

The source code files are important, but without any textures, sounds, and 3D models you would not have a real game. Because the XnaShooter XACT project was already discussed in Chapter 9, it is the first thing you are going to add to your new project. The only file that has to be in your project is the XnaShooter.xap file, but it uses many .wav files. I tend to add all these .wav files to the project too because I like to see which files are used directly in the project.

After the XACT project is added to the Sounds namespace you can change the Sound class and test all the sounds with help of the TestPlaySounds unit test. The unit test does not cover all sounds, but the most important sound effects are tested here. Some sounds like GameMusic and Explosion are using more than one sound file. This means if you play the Explosion sound one of three explosion sound files is randomly selected and played. There is no special code required for this to work; everything is set up in XACT.

  public static void TestPlaySounds() {   TestGame.Start(     delegate     {       if (Input.MouseLeftButtonJustPressed ||         Input.GamePadAJustPressed)         Sound.Play(Sounds.Defeat);       else if (Input.MouseRightButtonJustPressed ||         Input.GamePadBJustPressed)         Sound.Play(Sounds.Victory);       else if (Input.KeyboardKeyJustPressed(Keys.D1))         Sound.Play(Sounds.GameMusic);       else if (Input.KeyboardKeyJustPressed(Keys.D2))         Sound.Play(Sounds.EnemyShoot);       else if (Input.KeyboardKeyJustPressed(Keys.D3))         Sound.Play(Sounds.Explosion);       else if (Input.KeyboardKeyJustPressed(Keys.D4))         Sound.Play(Sounds.Health);       else if (Input.KeyboardKeyJustPressed(Keys.D5))         Sound.Play(Sounds.PlasmaShoot);       else if (Input.KeyboardKeyJustPressed(Keys.D6))         Sound.Play(Sounds.MgShoot);       else if (Input.KeyboardKeyJustPressed(Keys.D7))         Sound.Play(Sounds.GattlingShoot);       else if (Input.KeyboardKeyJustPressed(Keys.D8))         Sound.Play(Sounds.EMP);       TextureFont.WriteText(2, 30,         "Press 1-8 or A/B or left/right mouse buttons to play back "+         "sounds!");     }); } // TestPlaySounds() 

User Interface

The UI and menu textures should be added now. The previous chapter talked quite a bit about handling the input, the UI, and the game screen’s logic, so just add the required files (MainMenu.png, MouseCursor.dds, and GameFont.png) and take a look at the game screen logic (see Figure 11-2). Implementing the main menu and the other game screens should not take long. It is very similar to the Rocket Commander game, but several complicated screens like the Options and Mission Selection screens were removed because they were not really necessary for XnaShooter.

image from book
Figure 11-2

You already learned about the in-game UI for XnaShooter, and the game logic for the whole game is discussed at the end of this chapter. For the menu you only have three screens and all of them are easy to implement. The Main Menu just shows four menu buttons, which add a new game screen on the stack to allow you to return to the main menu after quitting the newly added game screen. The Highscore list is a stripped-down version of the Rocket Commander Highscore screen just showing a local highscore because there is no network support for an online highscore in XNA. Last but not least, the Credits screen just shows a bunch of text plus the Back button.

Take a quick look at the MainMenu Run method, which handles the main menu and the four buttons to the other game screens:

  // Render background game.RenderMenuBackground(); // Show all buttons int buttonNum = 0; foreach (MenuButton button in menuButtons)   // Don't render the back button   if (button != MenuButton.Back)   {     if (game.RenderMenuButton(button, buttonLocations[buttonNum]))     {       if (button == MenuButton.Missions)         game.AddGameScreen(new Mission());       else if (button == MenuButton.Highscore)         game.AddGameScreen(new Highscores());       else if (button == MenuButton.Credits)         game.AddGameScreen(new Credits());       else if (button == MenuButton.Exit)         quit = true;     } // if     buttonNum++;     if (buttonNum >= buttonLocations.Length)       break;   } // foreach if // Hotkeys, M=Mission, H=Highscores, C=Credits, Esc=Quit if (Input.KeyboardKeyJustPressed(Keys.M))   game.AddGameScreen(new Mission()); else if (Input.KeyboardKeyJustPressed(Keys.H))   game.AddGameScreen(new Highscores()); else if (Input.KeyboardKeyJustPressed(Keys.C))   game.AddGameScreen(new Credits()); else if (Input.KeyboardEscapeJustPressed)   quit = true; 

Textures

In addition to the menu, mouse, and game font textures you need a bunch more textures for the game. First of all there are the HUD textures you already saw in the previous chapter and the new NumbersFont.png texture for some colorful numbers you are going to display on the top HUD bar. Then there are also many effect textures you need for the effect system discussed later in this chapter. It is hard to explain which texture is used for which part of the game; please just take a look at Figure 11-3 for a quick explanation on how each texture is used in XNA Shooter.

image from book
Figure 11-3

All these texture files have to be added to the project, but the content importer settings are not all the same. Some files like the mouse cursor, the main menu, and the game font should not be compressed with the DXT compression format (used in dds files). They should stay uncompressed in 32bpp (bits per pixel), but other textures like the explosion effects need compression to become smaller. For example, the BigExplosion effect consists of about 30 textures with the size 128x128. Without compression this would be about 2 MB of texture data just for one explosion effect.

With DXT5 compression you can get it down to half an MB, allowing you to implement several explosion effects and still save disk and video memory space. To support the alpha channel of the explosion textures the DXT5 compression format has to be used instead of DXT1, which would compress even better.

The game has about 3 MB of textures, where 1 MB is just for the two explosion effects and another MB goes to the menu graphics. The rest of the textures are used for the visual effects, the HUD, and fonts. Effect systems can be much more complex with many little particles acting together to form cool big explosions. Sometimes effects are even combined with a physics engine and allow you to let the particles, smoke, and explosion pieces interact with the 3D environment and even with each other.

For the XnaShooter game the simple effect system is sufficient; all effects are hard coded, but it is very easy to change them or to add new effects using the existing textures. Just add another Add method and test it with help of the TestEffects unit test in the EffectManager class.

3D Models

The game uses a lot of 3D models (see Figure 11-4). I just started with a ship and some effects, but after a while I noticed that the game would be no fun without at least 3–4 different enemy units that behave differently. The units in XNA Shooter are very different:

  • OwnShip is the model for your own ship. It allows you to shoot with an MG, Plasma, Gatling-Gun, or the Rocket Launcher. Additionally you can fire EMP bombs to kill everything on the screen. Your ship is the fastest one in the game, but when the screen gets filled with enemy units, that won’t help you; you have to kill everything before the enemies can overwhelm you.

  • Corvette is the basic enemy unit; it shoots two small MGs mounted on the left and right side of the ship. It does not have many hitpoints and the weapon is very weak. The main advantage this unit has is the fact that the weapon hits you instantly if you are in the shooting direction of the Corvette. If the screen fills up with many Corvettes you will constantly lose energy if you don’t kill them fast enough.

  • Small-Transporter is a little ship that carries supplies. There’s a 25% to 50% chance these ships have something useful for you, especially health items, which are useful if you are low on health, and EMP bombs can be collected after you kill these transporters. They carry all the other items too, allowing you to switch your weapon after collecting new weapon items. Transporters do not shoot, but you should not collide with them. They are small and have even fewer hitpoints than the Corvette ship.

  • The Firebird is a very powerful unit because it shoots fireballs directly at you. It even calculates the position you are currently flying to forcing you to constantly evade the incoming fireballs. It has more hitpoints than the other smaller ships and it is a little bigger. Do not collide with Firebirds; they can immensely reduce your energy. Often only an EMP can help you if too many Firebirds are on the screen.

  • The Rocket-Frigate is the biggest ship in the game. Originally I also wanted to create a BossEnemy at the end of the level, but it was too much work creating the 3D model and implementing the additional game logic. It should not be hard to add a Boss-Enemy and more levels to the game if you are really interested in developing a shoot-’em-up game. The Rocket-Frigate fires rockets, similar to the rockets your own ship can fire, but they are a lot smaller and do not inflict as much damage. In addition to the heavy armor and high amount of hitpoints this unit has, the main advantage of the rockets that are fired by the Rocket-Frigate is the homing ability of the rockets, which will always follow your ship until they run out of fuel. Handling just one Rocket-Frigate is no big problem. If you are skilled enough to evade the incoming rockets and are able to still hit the Rocket-Frigate, it will be demolished after a short while. It becomes a lot harder if you have to deal with multiple Rocket-Frigates at the end of the mission. Make sure you have a heavy weapon and EMP bombs on your ship to prepare for these situations.

  • Asteroids are not really a unit; they just fly around and block your way. They cannot shoot, but if you collide with them you lose a high amount of hitpoints. They are almost indestructible with normal weapons, but with help of EMP bombs you are able to take them out. You have probably noticed that I stole this model from the Rocket Commander game.

image from book
Figure 11-4

The units are very important for your game, but without the items it would be no fun and without the background objects it would look too boring. The items give you back health or EMP bombs or allow you to change the weapon to the four available weapons: MG, Plasma Gun, Gatling-Gun, and the Rocket Launcher.

The background objects do not interact with the game at all; they just sit in the background and receive shadows. First the LandscapeBackground.X model is rendered and repeated for the mission. Later in this chapter you learn more details about the creation process and the level generation. After rendering the landscape all buildings and plants are rendered on top of it. Because the center of the landscape model forms a valley that has the same height at all locations you can easily add the buildings and plants here. All the objects are randomly added and generated as you fly through the level. You can also add more objects if you want to. It is very easy to change the landscape models list; just add another model and it will automatically be generated on the ground.

Animated Textures

You already used animated textures before in the Rocket Commander game, but you never learned how to implement them. Basically you just have a bunch of textures, which are changed every 1/30 of a second. In XNA Shooter two animated textures are implemented for the two explosion effects used when units explode. You could just load the 30 textures for each explosion effect and handle them yourself, but because you need that code more than once it should be abstracted to a new class: AnimatedTevaxture (see Figure 11-5).

image from book
Figure 11-5

The constructor of AnimatedTexture is very similar to the Texture constructor, but you also check for additional textures with the help of the filename. The big explosion has sequential texture names like BigExplosion0001.dds, BigExplosion0002.dds, BigExplosion0003.dds, and so on. The following code in the constructor is used to load all these filenames into the internal xnaTextures array. Please note that in the original Rocket Commander code (Managed DirectX) dds files were loaded, but in XNA you should load the already compiled .xnb files, which is the only way to load textures on the Xbox 360 (the Windows platform, however, also supports loading directly from dds files).

  // Ok, now load all other animated textures List<XnaTexture> animatedTextures =   new List<XnaTexture>(); animatedTextures.Add(internalXnaTexture); int texNumber = 2; while (File.Exists(filenameFirstPart +   texNumber.ToString("0000")+".xnb")) {   animatedTextures.Add(BaseGame.Content.Load<Texture2D>(     filenameFirstPart + texNumber.ToString("0000")));   texNumber++; } // while (File.Exists) xnaTextures = animatedTextures.ToArray(); 

With the help of the Select method you can now select any of the loaded textures, and the rest of the class behaves exactly the same as the original texture class. This means you can select and render textures on the screen or pass the texture to shaders because the internal xnaTexture field is assigned to the correct selected texture. You can also just call GetAnimatedTexture to access any animated texture number yourself.

  /// <summary> /// Select this animated texture as the current texture /// </summary> /// <param name="animationNumber">Number</param> public void Select(int animationNumber) {   if (xnaTextures != null &&     xnaTextures.Length > 0)   {     // Select new animation number     internalXnaTexture =       xnaTextures[animationNumber % xnaTextures.Length];   } // if } // Select(num) 

Billboards

You now have all the content in place for your XNA Shooter game. You still need to think about a way to display all this new content. You do not have any rendering code for the landscape and all the objects on it yet and you don’t have code to display the new effects in your 3D environment. In Rocket Commander you just displayed the explosion, the only effect you had there, directly on the screen. In your new game it would not look very convincing to put all effects directly on top of the screen. Having the effects directly in your 3D scene as 3D polygons has several advantages:

  • You don’t need to calculate the 2D position and size for every 3D effect. When using 3D polygons they will be transformed to the screen like everything else.

  • Thanks to the depth buffer it is possible to render effects in front of and behind of other 3D objects. This way flare and smoke effects behind the ship engines look correct even if parts of the ship or other 3D objects are in front.

  • If you sort the effects back to front you can render them on top of each other with alpha blending turned. This way many effects are combined to give greater looking 3D effects.

To be able to render 3D effects directly on the screen, billboards are usually used. Billboards are just 3D quads (two triangles) showing the texture. Sometimes special graphic card features like point sprites can be used. In any case the billboards should be visible when you view them. But as with any 3D polygons, if they face in the wrong direction you can’t see them or they get distorted and smaller (see Figure 11-6).

image from book
Figure 11-6

For some effects this behavior is good; for example, a 3D explosion ring would look correct from the front and the sides except maybe from a 90 degree angle, when it almost disappears. Most other effects, however, are not designed to look good from the side. Explosions, light effects, fire and plasma balls, and so on are all effects that are captured from the front, but they look similar or just like it from all other sides too. Take the fireball effect as an example. A fireball should look like a ball from all directions; it should not be distorted, become small, or disappear if you look from the other side. To achieve that you have to make sure you always look the effect in the eye, so to speak. This is accomplished by always rotating the effect polygons in a way that faces directly to the viewer. The Billboard class helps you achieve this task (see Figure 11-7).

image from book
Figure 11-7

The most important methods of the Billboard class are the Render methods that put the billboards into the billboards list, which is finally rendered when you call RenderBillboards at the end of each frame. There are six overloads of the Render method, but you can also call the RenderOnGround methods to render billboards on the xy plane. One of the Render methods even allows you to specify the right and up vectors, which span the billboard vectors. This way you can randomly align explosion rings for the ship explosion in addition to the other explosion effects.

Before you take a look at the Render methods, check out the unit test of the Billboard class, which shows you how to use this class:

  Billboard.Render(plasma,   new Vector3(-40.0f, 0.0f, 0.0f), 5.0f,   BaseGame.TotalTimeMs * (float)Math.PI / 1000.0f,   Color.White); Billboard.Render(fireball,   new Vector3(-40.0f, +50.0f, 0.0f), 5.0f, 0,   Color.White); Billboard.RenderOnGround(ring,   new Vector3(-25.0f, 0.0f, -100.0f), 5.0f, 0, Color.White,   vecGroundRight, vecGroundUp); // etc. // Render all billboards for this frame Billboard.RenderBillboards(); 

In the Render methods the vecRight and vecUp vectors are used to construct the billboard polygons. These vectors can be directly extracted from the view matrix you currently use. Thanks to the BaseGame class it is easy to extract these vectors, which is automatically done every time you call RenderBillboards through the CalcVectors helper method.

  /// <summary> /// Calc vectors for billboards, will create helper vectors for /// billboard rendering, should just be called every frame. /// </summary> public static void CalcVectors() {   // Only use the inverse view matrix, world matrix is assumed to be   // Idendity, simply grab the values out of the inverse view matrix.   Matrix invViewMatrix = BaseGame.InverseViewMatrix;   vecRight = new Vector3(     invViewMatrix.M11, invViewMatrix.M12, invViewMatrix.M13);   vecUp = new Vector3(     invViewMatrix.M21, invViewMatrix.M22, invViewMatrix.M23); } // CalcVectors() 

Take a quick look at one of the Render methods of the Billboard class:

  /// <summary> /// Render 3D Billboard into scene. Used for 3D effects. /// This method does not support rotation (it is a bit faster). /// </summary> /// <param name="tex">Texture used for rendering</param> /// <param name="lightBlendMode">Blend mode for this effect</param> /// <param name="pos">Position in world space</param> /// <param name="size">Size in world coordinates</param> /// <param name="col">Color, usually white</param> public static void Render(XnaTexture tex, BlendMode lightBlendMode,   Vector3 pos, float size, Color col) { // Invisible? if (col.A == 0)   return; TextureBillboardList texBillboard =   GetTextureBillboard(tex, lightBlendMode); Vector3 vec; int index = texBillboard.vertices.Count; vec = pos + ((-vecRight + vecUp) * size); texBillboard.vertices.Add(   new VertexPositionColorTexture(   vec, col, new Vector2(0.0f, 0.0f))); vec = pos + ((-vecRight - vecUp) * size); texBillboard.vertices.Add(   new VertexPositionColorTexture(   vec, col, new Vector2(0.0f, 1.0f))); vec = pos + ((vecRight - vecUp) * size); texBillboard.vertices.Add(   new VertexPositionColorTexture(   vec, col, new Vector2(1.0f, 1.0f))); vec = pos + ((vecRight + vecUp) * size); texBillboard.vertices.Add(   new VertexPositionColorTexture(   vec, col, new Vector2(1.0f, 0.0f))); texBillboard.indices.AddRange(new short[]   {    (short)(index+0), (short)(index+1), (short)(index+2),    (short)(index+0), (short)(index+2), (short)(index+3),     }); } // Render(tex, pos, size) 

As you can see, four vertices are constructed and added to the vertices list for this billboard type. Each texture and light blend mode combination gets its own TextureBillboardList. Then indices for the two polygons that form a screen quad are added to the indices list. Both the vertex and index buffers from the TextureBillboardList are then rendered together with the texture and the effect shader in the RenderBillboards method.




Professional XNA Game Programming
Professional XNA Programming: Building Games for Xbox 360 and Windows with XNA Game Studio 2.0
ISBN: 0470261285
EAN: 2147483647
Year: 2007
Pages: 138

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