Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
578,49 KB
Nội dung
330 | Chapter 14: Particle Systems What You Just Did Before we get into all of that, let’s review what you did this chapter: • You learned about particles and particle systems. • You created a custom vertex. • You created a particle engine that moves, adds, and removes particles to create a sphere-shaped explosion. • You created an HLSL effect file that sets the size of the vertices and sets the col- ors based on texture coordinates. • You created a starfield background using a modified particle engine that draws particles but doesn’t remove them or move them around. Figure 14-5. Stars make the game look much more realistic Test Your Knowledge: Quiz | 331 Summary • A particle is simply a way of representing a single element within a group of ele- ments that form a particle effect, such as an explosion or some magical spell effect. • A particle engine is a mechanism that manipulates, adds, removes, and draws particles to make up a particle effect. Often, particle engines simulate gravity and other external forces to make particle effects look more realistic. • In addition to using vertex types such as VertexPositionColor and VertexPositionTexture, you can create your own customized vertex types pro- viding any kind of information you want. To understand your vertex type, the graphics card needs a VertexDeclaration specifying what members exist in the vertex type and what data to send to certain semantics in HLSL. • Point sprites were introduced in DirectX 8 as a way to allow developers to draw particles or other effects using only one vertex per particle. • In HLSL you can specify the size of a vertex using the PSIZE[n] semantic, which will let you create point sprites that vary in size. • Anyone who knows XNA and can create sweet particle effects will have more friends than they know what to do with. Test Your Knowledge: Quiz 1. If you want to get texture coordinates to your pixel shader, what do you have to do in the vertex shader? 2. What semantic affects the size of a vertex? Where would you assign a value to a variable using that semantic for the size to take effect? 3. How are semantics connected to C# code when creating a custom vertex? 4. What is a particle engine? 5. What is a point sprite, and why are they important? 6. What are texture (U, V) coordinates? 7. According to Napoleon Dynamite, how much time does it take him to make $120? 332 Chapter 15 CHAPTER 15 Wrapping Up Your 3D Game 15 Here we go—you’re at the final stage in the development of your first 3D game. It looks good, sounds good, and plays well, and all that’s left to do is to add some game logic and wrap it up. First things first, you need a splash screen when your game starts. In addition, you’ll need to provide the player with some kind of an indi- cator when she reaches another level in the game. Why not use a splash screen between levels, too? Finally, you’ll need to have a screen that displays the final score when the game is over. Sounds like a good solution to these problems would be to create a splash screen game component that will let you display text on the screen. That way, you can reuse the same class for all three purposes just mentioned—and let’s face it, anytime you can reuse code, you’re saving yourself all kinds of time and headaches. This chapter picks up where Chapter 14 left off. Open the project that you were working on at the end of Chapter 14 and use it throughout this chapter. Adding a Splash Screen Game Component Before we jump in and code your splash screen component, let’s step back and look at how this is going to work. Your Game1 class is going to manage different game states. Several states are possible: starting the game, playing the game, pausing the game between levels, and showing a game-over screen at the end of the game. To help you manage these states, create an enum in your Game1 class that you will use to track changes from state to state during gameplay. Add the following lines of code at the class level of your Game1 class: public enum GameState { START, PLAY, LEVEL_CHANGE, END} GameState currentGameState = GameState.START; In these lines, you first define an enum called GameState that enumerates all the possi- ble game states, and then you create a variable that you’ll use to track the current game state and initialize that variable to the START game state. That should be help- ful as you move through this chapter. Adding a Splash Screen Game Component | 333 You’ll also need to add a way for the splash screen game component and the model manager game component to notify the Game1 class when a change in game state occurs. To that end, add the following method to the Game1 class: public void ChangeGameState(GameState state, int level) { currentGameState = state; } Later, you’ll add more logic to this method that will make use of the second parame- ter and will perform different tasks based on the changed game state. For now, this will do. To add a splash screen game component, you’ll first need to create a blank game com- ponent class. Add a game component to your project and call the file SplashScreen.cs. Remember that by default a game component does not have a Draw method and there- fore will not draw anything. But, what good would a splash screen component be if you couldn’t use it to draw text? Change the base class of the new game component from GameComponent to DrawableGameComponent, which will let your game component tie into the game loop’s Draw sequence. Next, add the following class-level variables to your splash screen game component: string textToDraw; string secondaryTextToDraw; SpriteFont spriteFont; SpriteFont secondarySpriteFont; SpriteBatch spriteBatch; Game1.GameState currentGameState; Your splash screen will have the ability to display a header in a larger font and some other text in a smaller font. The two SpriteFont variables and the SpriteBatch variable are included to facilitate the drawing of that text. Your currentGameState variable will track the current game state, so your splash screen will know what to do based on what state the game is currently in. As you’ve probably guessed based on the SpriteFont variables you added, you now need to add a couple of spritefonts to your project. Right-click the Content node in Solution Explorer and select Add ➝ New Folder. Name the new folder Fonts. Then right-click the new Fonts folder and select Add ➝ New Item Select the Sprite Font template on the right and name your font Arial.spritefont, as shown in Figure 15-1. Next, add another spritefont (following the same steps), and call this one Arial Black. spritefont. You’re going to use the Arial Black sprite font for the larger title text in the window. Open that file, and you’ll see that the content is XML-based. The second element of the font is a <Size> element. Change your Arial Black sprite font’s size to 16 by modi- fying that element as follows: <Size>16</Size> 334 | Chapter 15: Wrapping Up Your 3D Game To make the larger text stand out a bit more, go ahead and modify the size of the Arial sprite font as well. Open the Arial.spritefont file and change the font to be smaller (size 10): <Size>10</Size> Next, in your SplashScreen class, you’ll need to add an override for the LoadContent method so you can load the sprite fonts and initialize your SpriteBatch object. Add the following code in the SplashScreen class: protected override void LoadContent( ) { // Load fonts spriteFont = Game.Content.Load<SpriteFont>(@"fonts\Arial Black"); secondarySpriteFont = Game.Content.Load<SpriteFont>(@"fonts\Arial"); // Create sprite batch spriteBatch = new SpriteBatch(Game.GraphicsDevice); base.LoadContent( ); } Your splash screen will display at the beginning of the game, at the end of the game, and between levels. But how will you make the game transition from splash screen to gameplay or game exit? What’s the best way to do that? That’s a good question, and there really is no right answer. This is another aspect of game development that comes down to personal preference. Often, splash screens are time-based and will fade to the next game state after a few moments. Others may disappear when a key is pressed or a mouse button is clicked. Still others aren’t even separate screens, but are just overlaid during gameplay and fade out slowly. Exactly how you want to do this is all up to you. Figure 15-1. Creating a new sprite font Adding a Splash Screen Game Component | 335 For the purposes of this book, we’re going to make the screens transition by press- ing the Enter key. To implement that, you’ll need to catch any Enter key presses in the Update method of your SplashScreen class. If an Enter key press is detected, you’ll either notify the Game1 class that a change in game state is needed, or exit the game completely. Which of those you do depends on the current game state (i.e., is the SplashScreen component currently showing a start or level-change screen, or a game- over screen?). Change the Update method of your SplashScreen class to the following: public override void Update(GameTime gameTime) { // Did the player hit Enter? if (Keyboard.GetState( ).IsKeyDown(Keys.Enter)) { // If we're not in end game, move to play state if (currentGameState == Game1.GameState.LEVEL_CHANGE || currentGameState == Game1.GameState.START) ((Game1)Game).ChangeGameState(Game1.GameState.PLAY, 0); // If we are in end game, exit else if (currentGameState == Game1.GameState.END) Game.Exit( ); } base.Update(gameTime); } Because the splash screen should never be displayed during the PLAY game state, the only states that you’re checking for are START, LEVEL_CHANGE, and END. If the current state is either of the first two, you’re going to transition to a PLAY state, so you call the Game1 class’s ChangeGameState and notify the class of that change. If the current state is END, the game exits when the player presses the Enter key. Next, you need to add the code that will actually draw the text. Of course, this is done in a Draw method, which you currently do not have. You’ll need to create an override of the Draw method and add the code to draw the large title text and the smaller subtitle text: public override void Draw(GameTime gameTime) { spriteBatch.Begin( ); // Get size of string Vector2 TitleSize = spriteFont.MeasureString(textToDraw); // Draw main text spriteBatch.DrawString(spriteFont, textToDraw, new Vector2(Game.Window.ClientBounds.Width / 2 - TitleSize.X / 2, Game.Window.ClientBounds.Height / 2), Color.Gold); 336 | Chapter 15: Wrapping Up Your 3D Game // Draw subtext spriteBatch.DrawString(secondarySpriteFont, secondaryTextToDraw, new Vector2(Game.Window.ClientBounds.Width / 2 - secondarySpriteFont.MeasureString( secondaryTextToDraw).X / 2, Game.Window.ClientBounds.Height / 2 + TitleSize.Y + 10), Color.Gold); spriteBatch.End( ); base.Draw(gameTime); } Notice that the first call to DrawString uses the larger SpriteFont object and centers the text using the screen width and height, as well as the TitleSize Vector2 object, which holds the size of the title text as given by the SpriteFont.MeasureString method. The second DrawString call also centers the text horizontally the same way, but it places the text vertically just below the title text by using the size of the title text as an offset. The final piece of the SplashScreen class is a method that will enable the Game1 class to set the text that needs to be displayed and to set the current game state. Add this method to the SplashScreen class: public void SetData(string main, Game1.GameState currGameState) { textToDraw = main; this.currentGameState = currGameState; switch (currentGameState) { case Game1.GameState.START: case Game1.GameState.LEVEL_CHANGE: secondaryTextToDraw = "Press ENTER to begin"; break; case Game1.GameState.END: secondaryTextToDraw = "Press ENTER to quit"; break; } } The secondary text is set depending on the game state, while the primary text is passed into the method with the new game state. Now that your SplashScreen class is ready to go, all you need to do is hook up the component to your game. Add a SplashScreen variable at the class level of your Game1 class, together with a variable to keep track of scoring. You’ll be adding scoring to the game later, and you’ll want to display the player’s score when the game is over: SplashScreen splashScreen; int score = 0; Adding a Splash Screen Game Component | 337 Next, you’ll need to initialize the SplashScreen component and add it to the list of game components in Game1’s Initialize method. Currently, the method looks like this: protected override void Initialize( ) { camera = new Camera(this, new Vector3(0, 0, 50), Vector3.Zero, Vector3.Up); Components.Add(camera); modelManager = new ModelManager(this); Components.Add(modelManager); base.Initialize( ); } Modify the Initialize method as shown here (added lines in bold): protected override void Initialize( ) { camera = new Camera(this, new Vector3(0, 0, 50), Vector3.Zero, Vector3.Up); Components.Add(camera); modelManager = new ModelManager(this); Components.Add(modelManager); modelManager.Enabled = false; modelManager.Visible = false; // Splash screen component splashScreen = new SplashScreen(this); Components.Add(splashScreen); splashScreen.SetData("Welcome to Space Defender!", currentGameState); base.Initialize( ); } The first two lines are added directly after the Components.Add(modelManager) line. These lines disable the modelManager component. Why are you doing this? Because you’re going to begin your game with the splash screen. When the splash screen is active, the model manager needs to be inactive, and vice versa. Next, you initialize the SplashScreen component, add it to the list of components, and set its initial val- ues via the SetData method. The next thing you’ll need to look at is the Update method. Currently, every time Update is called, you’re checking the keyboard for a space bar key press and, if one occurs, firing a shot. You’re only going to want to do this now if the current game state is set to PLAY. The current Update method of your Game1 class should look something like this: 338 | Chapter 15: Wrapping Up Your 3D Game protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit( ); // See if the player has fired a shot FireShots(gameTime); base.Update(gameTime); } Surround the call to the FireShots method with an if statement so that new shots will only be fired if the game is in the PLAY state: // Only check for shots if you're in the play game state if (currentGameState == GameState.PLAY) { // See if the player has fired a shot FireShots(gameTime); } Next, you’ll need to do the same sort of thing in the Draw method, as you’re cur- rently drawing a crosshair every time that method is called. Surround that code with a similar if statement so that the crosshair is drawn only if the game is in the PLAY state (added code in bold): protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Black); // TODO: Add your drawing code here base.Draw(gameTime); // Only draw crosshair if in play game state if (currentGameState == GameState.PLAY) { // Draw the crosshair spriteBatch.Begin( ); spriteBatch.Draw(crosshairTexture, new Vector2((Window.ClientBounds.Width / 2) - (crosshairTexture.Width / 2), (Window.ClientBounds.Height / 2) - (crosshairTexture.Height / 2)), Color.White); spriteBatch.End( ); } } Adding a Splash Screen Game Component | 339 Finally, you’ll need to flesh out the ChangeGameState method. Currently, all it does is set the currentGameState variable. You’ll need to add some action to stop or play the soundtrack music and enable/disable the splash screen and model manager compo- nents, based on the game state to which the game is transitioning. Modify the method as follows: public void ChangeGameState(GameState state, int level) { currentGameState = state; switch (currentGameState) { case GameState.LEVEL_CHANGE: splashScreen.SetData("Level " + (level + 1), GameState.LEVEL_CHANGE); modelManager.Enabled = false; modelManager.Visible = false; splashScreen.Enabled = true; splashScreen.Visible = true; // Stop the soundtrack loop trackCue.Stop(AudioStopOptions.Immediate); break; case GameState.PLAY: modelManager.Enabled = true; modelManager.Visible = true; splashScreen.Enabled = false; splashScreen.Visible = false; if (trackCue.IsPlaying) trackCue.Stop(AudioStopOptions.Immediate); // To play a stopped cue, get the cue from the soundbank again trackCue = soundBank.GetCue("Tracks"); trackCue.Play(); break; case GameState.END: splashScreen.SetData("Game Over.\nLevel: " + (level + 1) + "\nScore: " + score, GameState.END); modelManager.Enabled = false; modelManager.Visible = false; splashScreen.Enabled = true; splashScreen.Visible = true; // Stop the soundtrack loop trackCue.Stop(AudioStopOptions.Immediate); break; } } [...]... System.Collections.Generic; System.Linq; Microsoft .Xna. Framework; Microsoft .Xna. Framework.Audio; Microsoft .Xna. Framework.Content; Microsoft .Xna. Framework.GamerServices; Microsoft .Xna. Framework.Graphics; Microsoft .Xna. Framework.Input; Microsoft .Xna. Framework.Media; Microsoft .Xna. Framework.Net; Microsoft .Xna. Framework.Storage; namespace _3D_Game { public class Camera : Microsoft .Xna. Framework.GameComponent { //Camera... 16-1 Now that you have a connection key, you’ll need to connect your PC to your Xbox 360 using this key Start the XNA Game Studio Device Center on your PC The Device Center is installed with XNA Game Studio 3.0; you can find it under Start ➝ All Programs ➝ Microsoft XNA Game Studio 3.0 ➝ XNA Game Studio Device Center Once you load the Device Center, it will display a list of known devices If this is... DreamSpark program or through MSDNAA (the MSDN Academic Alliance) See http:// forums .xna. com/forums/t/12661.aspx Once you’ve obtained your memberships, you’ll need to download XNA Game Studio Connect You can get XNA Game Studio Connect in the Xbox LIVE Marketplace by selecting Game Store ➝ More ➝ Genres ➝ Other ➝ XNA Creators Club Now, you’re ready to generate your connection key To generate the key,... live at the end of 20 08, will allow members of the XNA Creators Club to submit games for review to make sure they are safe to play Once the game is approved by a group of peers within the Xbox Creators Club, the developer can set a price point for his game The game is then made available to users worldwide as a purchasable download via Xbox LIVE Marketplace What a great time to be an XNA game developer,... your Xbox 360 to the Device Center (see Figure 16-2) After clicking Add Device, XNA Game Studio Device Center will ask you which type of device you want to add by displaying the screen shown in Figure 16-3 Select Xbox 360 and click Next Adding an Xbox 360 Device | 355 Figure 16-1 XNA Game Studio Connect screen Figure 16-2 XNA Game Studio Device Center You’ll then be asked to give your Xbox 360 a name... appears on your XNA Game Studio Connect screen Adding an Xbox 360 Device | 357 Figure 16-5 Enter your Xbox 360 connection key Once you’ve entered your connection key, the XNA Game Studio Device Center will search for the Xbox 360 and add it to the device list Converting a Project to Run on the Xbox 360 Now that you have a connected Xbox 360, let’s see just how easy it is to deploy an XNA Game Studio... Your Knowledge: Exercise | 353 Chapter 16 16 CHAPTER Deploying to the Xbox 360 16 One of the most compelling reasons to learn XNA and write games using the XNA Framework is the fact that it enables developers to develop their own games and play them on the Xbox 360 Prior to XNA, it was nearly impossible for hobbyist developers to gain access to the tools needed to develop games for a next-generation... console, but with the XNA Framework, they can write games that will run on the PC and the Xbox 360 in one environment and with one code base In addition, Xbox LIVE Marketplace is being tweaked at the time of this writing to enable users to share games easily with users worldwide Never before has the window of opportunity been opened so widely for console development In July 20 08, an announcement was... your connection key To generate the key, follow these steps: 1 Select the Games tab in the Xbox 360 dashboard 2 Select the Games Library option 3 Select My Games 4 Select XNA Game Studio Connect 5 Select Launch You should see the XNA Game Studio Connect screen, which will look something like Figure 16-1 Note that the key listed in Figure 16-1 will not be the same as the one that you have on your screen... completion, you can create a copy of the project for development on the Xbox 360 and concentrate on Xbox 360-specific debugging 3 58 | Chapter 16: Deploying to the Xbox 360 This is the method that is laid out in this book You have, from the previous chapter, a complete game written using XNA for Windows Open that project and create a copy of the project for the Xbox 360 by right-clicking the project in Solution . shotDelayRapidFire = 100 ; int rapidFireTime = 100 00; int powerUpCountdown = 0; string powerUpText = ""; 34 8 | Chapter 15: Wrapping Up Your 3D Game int powerUpTextTimer = 0; SpriteFont powerUpFont; Let’s. bold): protected override void Initialize( ) { camera = new Camera(this, new Vector3 (0, 0, 50) , Vector3.Zero, Vector3.Up); Components.Add(camera); modelManager = new ModelManager(this); Components.Add(modelManager); . required. Figure 15-4. 6 80 ! Simply amazing… Game Over. Level: 2 Score: 6 80 Press ENTER to quit Adding a Power-Up | 34 7 Adding a Power-Up You’ve done well here—you’ve built your first 3D game, complete