What significant change was made to the XNA folder structure in XNA 4.0?
The Content
node within your solution,
which was previously a subfolder of your game project, is now its
own project within your solution. This enables you to easily share
content across multiplatform projects.
What game platforms are supported with XNA 4.0?
XNA 4.0 supports development on Windows, Xbox 360, and Windows Phone 7 series.
What is the difference between the Reach and HiDef profiles in XNA 4.0?
HiDef is designed for high-powered, top-of-the-line hardware, whereas Reach is designed to support a wider range of hardware devices. The Reach profile offers a limited set of graphic features and is a subset of the HiDef profile.
Why do the Japanese tourists end up sleeping in a chest of drawers in Kramer’s apartment?
Because Kramer spent all their money, thinking that fifty-thousand yen was a huge sum of money they had at their disposal:
Elaine: Fifty-thousand yen? Isn’t that only a few hundred dollars?
Kramer: Evidently. Oh, by the way, tell Brett that his chest of drawers are a big hit. My guests are very comfortable in them.
Elaine: In them?!
Jerry: You have them sleeping in drawers?!
Kramer: Jerry, have you ever seen the business hotels in Tokyo? They sleep in tiny stacked cubicles all the time. They feel right at home.
Jerry: This has “international incident” written all over it.
Kramer: Oh yeah, yeah.
XNA Game Studio 4.0 allows you to write games for which platforms?
XNA 4.0 supports development for Windows Vista, Windows 7, the Xbox 360, and Windows Phone 7.
Which versions of Visual Studio support XNA Game Studio 4.0?
Either Visual Studio 2010 Standard Edition or higher (with C# language support installed) or Visual C# 2010 Express Edition.
What are the steps in an XNA game loop?
The XNA game loop consists of only two methods: Update
and Draw
.
If you wanted to load a Texture2D
object, in which method should you do that?
LoadContent
.
What line of code should you use to change the framerate of an XNA game to 20 fps?
Either of these lines will do the trick:
TargetElapsedTime = TimeSpan.FromMilliseconds(50); TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 50);
What should you pass in as the parameter of Content.Load
when loading a Texture2D
object?
The asset name of the texture image you want to load. You can find an image’s asset name by viewing its properties in Solution Explorer.
Fact or fiction: the content pipeline will let you know at compile time if you add an image to your project that it cannot parse.
Fact. The content pipeline runs a compilation step on all content (textures, models, sounds, etc.) and then outputs the result as an XNA-compatible formatted object. If this step fails during compilation, the result is a compilation error.
You’re drawing a sprite, and you want the background to be transparent. What steps do you need to take to draw it with a transparent background?
There are two ways to draw transparent images in XNA. The
first option has two requirements. First, the background of your
image itself must be transparent. If it isn’t, you’ll need to edit
the image in an image editor and give it a transparent background.
Second, BlendState.AlphaBlend
must be used (this is the default if no parameters are specified
in SpriteBatch.Begin
).
The second option is to make sure that the transparent portion of the image is solid magenta (255, 0, 255).
You have two sprites (A and B), and when they collide, you always want A to be drawn on top of B. What do you need to do?
There are two possible solutions: using SpriteSortMode.FrontToBack
, you can set
the layer depth of A to a value greater than that of B (both must
be within the range of 0 to 1); or, using SpriteSortMode.BackToFront
, you can set
the layer depth of A to a value lower than that of B.
What are the things you need to keep track of to cycle through a sprite sheet?
Current frame to draw, size of each individual frame, and number of columns and rows in your sprite sheet.
What was the first television series to command more than $1 million per minute for advertising?
Only the best show in this history of television: Seinfeld.
In this chapter, you built an example where two XNA logo images moved around the screen and bounced off the edges. Take the animated sprite example that you built at the end of this chapter and make the animated sprite move and bounce in a similar fashion—but in this case, make the animated sprite move in both X and Y directions and bounce off of all four edges of the screen.
This exercise is fairly straightforward, as it involves taking two examples from the chapter and merging pieces together. The animation aspect of the exercise is covered at the end of the chapter, and the movement and bouncing off screen edges is covered in the middle of the chapter.
One thing that might be tricky is moving in both X and Y directions at the same time. In the previous moving example, you used a float variable for the speed and added it to either the X or the Y coordinate, depending on which sprite you were moving (they both moved in only one direction).
Now I’d recommend using a Vector2
to represent speed. That way you can
have different values for speed in the X direction and the Y
direction. Also, you can add your Vector2
speed to your Vector2
position by simply adding the two
together (you can add Vector2
objects just as you would add integer or float values).
The other catch to this exercise is that in the previous moving
example you used the size of the Texture2D
object to determine how far from
the edge of the screen to bounce in the other direction, but now the
size of your Texture2D
object will
be inaccurate because you’re using a sprite sheet. Instead, you’ll
want to use the size of an individual frame within that sprite sheet
to detect when the image has hit the edge of the screen.
Here is one possible solution for this exercise:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace AnimatedSprites { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texture; Point frameSize = new Point(75, 75); Point currentFrame = new Point(0, 0); Point sheetSize = new Point(6, 8); //Framerate stuff int timeSinceLastFrame = 0; int millisecondsPerFrame = 16; //Speed and movement Vector2 speed = new Vector2(5, 2); Vector2 position = Vector2.Zero; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); } protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); texture = Content.Load<Texture2D>(@"Images hreerings"); } protected override void UnloadContent() { // TODO: Unload any non-ContentManager content here } protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Update time since last frame and only //change animation if framerate expired timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; if (timeSinceLastFrame > millisecondsPerFrame) { timeSinceLastFrame -= millisecondsPerFrame; ++currentFrame.X; if (currentFrame.X >= sheetSize.X) { currentFrame.X = 0; ++currentFrame.Y; if (currentFrame.Y >= sheetSize.Y) currentFrame.Y = 0; } } //Move sprite position += speed; //If the sprite hit a wall, reverse direction if (position.X > Window.ClientBounds.Width - frameSize.X || position.X < 0) speed.X *= -1; if (position.Y > Window.ClientBounds.Height - frameSize.Y || position.Y < 0) speed.Y *= -1; base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.White); spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend); spriteBatch.Draw(texture, position, new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); } } }
What object is used to read input from a mouse?
Mouse
.
Fact or fiction: the X and Y coordinates from a mouse as read in an XNA application represent how much the mouse has moved since the previous frame.
Fiction. The input is given in actual screen coordinates based off the upper-left corner of the game window. To get the distance moved since the previous frame, you have to compare the value from the current frame against the value of the previous frame.
What is the difference between an analog input control and a digital input control?
A digital input yields a Boolean yes/no, on/off status, whereas an analog input gives a range of inputs based on how far the button has been pressed.
Describe the bounding-box collision-detection algorithm.
The bounding-box algorithm is a simple collision-detection algorithm in which you “draw” imaginary boxes around objects and then run collision checks on the boxes themselves to see whether any objects are colliding.
Describe the pros and cons of the bounding-box collision-detection algorithm.
The two biggest pros of the algorithm are its speed and simplicity. The biggest drawback is its inherent inaccuracy—not all objects are square or rectangular, and as such, the algorithm has accuracy issues.
What is the ratio of unicorns to leprechauns?
According to Stanley Hudson of The Office, the ratio of unicorns to leprechauns equals the ratio of Stanley nickels to Schrute bucks.
Dwight: Don’t you want to earn Schrute bucks?
Stanley: No. In fact, I’ll give you a billion Stanley nickels if you never talk to me again.
Dwight: What’s the ratio of Stanley nickels to Schrute bucks?
Stanley: Same as the ratio of unicorns to leprechauns.
Let’s combine some aspects of this chapter and the previous one. Take the code where we left off at the end of this chapter and modify it to include another nonuser-controlled sprite (use the plus.png image, which is located with the source code for this chapter in the AnimatedSpritesAnimatedSpritesAnimatedSpritesContentImages folder). Add movement to both nonuser-controlled sprites, as you did in Chapter 3, so that each sprite moves in the X and Y directions and bounces off the edges of the screen. Add collision detection to the newly added sprite as well. The end result will be a game where you try to avoid two moving sprites. When you hit either sprite, the game ends.
For clarity in working with the plus.png image, the frame size of the sprite sheet is 75×75 pixels, and it has six columns and four rows (note that the rings and skull ball sprite sheets both had six columns and eight rows).
This exercise takes principles from Chapters 3 and 4 and combines them to create a very basic game where you try to avoid two sprites that move around the screen. The addition of a new animated sprite is a bit of a challenge, especially the way the code is currently written (in Chapter 5 you learned how to fine-tune the object-oriented design of the system you’re building). Other than that, collision detection and object movement and edge bouncing are handled the same way as in previous examples and should be fairly straightforward at this point. Here’s some sample code for this exercise:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace AnimatedSprites { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //Rings variables Texture2D ringsTexture; Point ringsFrameSize = new Point(75, 75); Point ringsCurrentFrame = new Point(0, 0); Point ringsSheetSize = new Point(6, 8); int ringsTimeSinceLastFrame = 0; int ringsMillisecondsPerFrame = 50; //Skull variables Texture2D skullTexture; Point skullFrameSize = new Point(75, 75); Point skullCurrentFrame = new Point(0, 0); Point skullSheetSize = new Point(6, 8); int skullTimeSinceLastFrame = 0; const int skullMillisecondsPerFrame = 50; //Plus variables Texture2D plusTexture; Point plusFrameSize = new Point(75, 75); Point plusCurrentFrame = new Point(0, 0); Point plusSheetSize = new Point(6, 4); int plusTimeSinceLastFrame = 0; const int plusMillisecondsPerFrame = 50; //Rings movement Vector2 ringsPosition = Vector2.Zero; const float ringsSpeed = 6; MouseState prevMouseState; //Skull position Vector2 skullPosition = new Vector2(100, 100); Vector2 skullSpeed = new Vector2(4, 2); //Plus position Vector2 plusPosition = new Vector2(200, 200); Vector2 plusSpeed = new Vector2(2, 5); //Collision detection variables int ringsCollisionRectOffset = 10; int skullCollisionRectOffset = 10; int plusCollisionRectOffset = 10; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); } protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures spriteBatch = new SpriteBatch(GraphicsDevice); ringsTexture = Content.Load<Texture2D>(@"images hreerings"); skullTexture = Content.Load<Texture2D>(@"imagesskullball"); plusTexture = Content.Load<Texture2D>(@"imagesplus"); } protected override void UnloadContent() { // TODO: Unload any non-ContentManager content here } protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Update time since last frame and only //change animation if framerate expired ringsTimeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; if (ringsTimeSinceLastFrame > ringsMillisecondsPerFrame) { ringsTimeSinceLastFrame -= ringsMillisecondsPerFrame; ++ringsCurrentFrame.X; if (ringsCurrentFrame.X >= ringsSheetSize.X) { ringsCurrentFrame.X = 0; ++ringsCurrentFrame.Y; if (ringsCurrentFrame.Y >= ringsSheetSize.Y) ringsCurrentFrame.Y = 0; } } //Then do the same to update the skull animation skullTimeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; if (skullTimeSinceLastFrame > skullMillisecondsPerFrame) { skullTimeSinceLastFrame -= skullMillisecondsPerFrame; ++skullCurrentFrame.X; if (skullCurrentFrame.X >= skullSheetSize.X) { skullCurrentFrame.X = 0; ++skullCurrentFrame.Y; if (skullCurrentFrame.Y >= skullSheetSize.Y) skullCurrentFrame.Y = 0; } } //Then do the same to update the plus animation plusTimeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; if (plusTimeSinceLastFrame > plusMillisecondsPerFrame) { plusTimeSinceLastFrame -= plusMillisecondsPerFrame; ++plusCurrentFrame.X; if (plusCurrentFrame.X >= plusSheetSize.X) { plusCurrentFrame.X = 0; ++plusCurrentFrame.Y; if (plusCurrentFrame.Y >= plusSheetSize.Y) plusCurrentFrame.Y = 0; } } //Move position of rings based on keyboard input KeyboardState keyboardState = Keyboard.GetState(); if (keyboardState.IsKeyDown(Keys.Left)) ringsPosition.X -= ringsSpeed; if (keyboardState.IsKeyDown(Keys.Right)) ringsPosition.X += ringsSpeed; if (keyboardState.IsKeyDown(Keys.Up)) ringsPosition.Y -= ringsSpeed; if (keyboardState.IsKeyDown(Keys.Down)) ringsPosition.Y += ringsSpeed; //Move the skull skullPosition += skullSpeed; if (skullPosition.X > Window.ClientBounds.Width - skullFrameSize.X || skullPosition.X < 0) skullSpeed.X *= -1; if (skullPosition.Y > Window.ClientBounds.Height - skullFrameSize.Y || skullPosition.Y < 0) skullSpeed.Y *= -1; //Move the plus plusPosition += plusSpeed; if (plusPosition.X > Window.ClientBounds.Width - plusFrameSize.X || plusPosition.X < 0) plusSpeed.X *= -1; if (plusPosition.Y > Window.ClientBounds.Height - plusFrameSize.Y || plusPosition.Y < 0) plusSpeed.Y *= -1; //Move rings based on mouse movement MouseState mouseState = Mouse.GetState(); if (mouseState.X != prevMouseState.X || mouseState.Y != prevMouseState.Y) ringsPosition = new Vector2(mouseState.X, mouseState.Y); prevMouseState = mouseState; //Move rings based on gamepad input GamePadState gamepadState = GamePad.GetState(PlayerIndex.One); if (gamepadState.Buttons.A == ButtonState.Pressed) { //A is pressed, double speed and vibrate ringsPosition.X += ringsSpeed * 2 * gamepadState.ThumbSticks.Left.X; ringsPosition.Y -= ringsSpeed * 2 * gamepadState.ThumbSticks.Left.Y; GamePad.SetVibration(PlayerIndex.One, 1f, 1f); } else { //A is not pressed, normal speed and stop vibration ringsPosition.X += ringsSpeed * gamepadState.ThumbSticks.Left.X; ringsPosition.Y -= ringsSpeed * gamepadState.ThumbSticks.Left.Y; GamePad.SetVibration(PlayerIndex.One, 0, 0); } //Adjust position of rings to keep it in the game window if (ringsPosition.X < 0) ringsPosition.X = 0; if (ringsPosition.Y < 0) ringsPosition.Y = 0; if (ringsPosition.X > Window.ClientBounds.Width - ringsFrameSize.X) ringsPosition.X = Window.ClientBounds.Width - ringsFrameSize.X; if (ringsPosition.Y > Window.ClientBounds.Height - ringsFrameSize.Y) ringsPosition.Y = Window.ClientBounds.Height - ringsFrameSize.Y; //If objects collide, exit the game if (Collide()) Exit(); base.Update(gameTime); } protected bool Collide() { Rectangle ringsRect = new Rectangle( (int)ringsPosition.X + ringsCollisionRectOffset, (int)ringsPosition.Y + ringsCollisionRectOffset, ringsFrameSize.X - (ringsCollisionRectOffset * 2), ringsFrameSize.Y - (ringsCollisionRectOffset * 2)); Rectangle skullRect = new Rectangle( (int)skullPosition.X + skullCollisionRectOffset, (int)skullPosition.Y + skullCollisionRectOffset, skullFrameSize.X - (skullCollisionRectOffset * 2), skullFrameSize.Y - (skullCollisionRectOffset * 2)); Rectangle plusRect = new Rectangle( (int)plusPosition.X + plusCollisionRectOffset, (int)plusPosition.Y + plusCollisionRectOffset, plusFrameSize.X - (plusCollisionRectOffset * 2), plusFrameSize.Y - (plusCollisionRectOffset * 2)); return ringsRect.Intersects(skullRect) || ringsRect.Intersects(plusRect); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.White); spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend); //Draw the rings spriteBatch.Draw(ringsTexture, ringsPosition, new Rectangle(ringsCurrentFrame.X * ringsFrameSize.X, ringsCurrentFrame.Y * ringsFrameSize.Y, ringsFrameSize.X, ringsFrameSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); //Draw the skull spriteBatch.Draw(skullTexture, skullPosition, new Rectangle(skullCurrentFrame.X * skullFrameSize.X, skullCurrentFrame.Y * skullFrameSize.Y, skullFrameSize.X, skullFrameSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); //Draw the plus spriteBatch.Draw(plusTexture, plusPosition, new Rectangle(plusCurrentFrame.X * plusFrameSize.X, plusCurrentFrame.Y * plusFrameSize.Y, plusFrameSize.X, plusFrameSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); } } }
What class does a game component derive from?
GameComponent
.
If you want to be able to draw on the screen with your game component, what class do you need to derive from?
DrawableGameComponent
.
Fact or fiction: time spent building a solid object-oriented design should not count as time spent developing software, because it is unnecessary and superfluous.
Absolutely fiction. Creating a proper design up front will help you avoid countless headaches and maintenance issues down the road. Always, no matter what the project, plan ahead and code around a solid design.
What is spontaneous dental hydroplosion?
As explained by Pam and Jim in The Office episode “Health Care”, spontaneous dental hydroplosion occurs when a person’s teeth turn to liquid and proceed to drip down the back of their throat.
Modify the code that you worked on this chapter to create four
sprites which move and bounce off all four edges of the screen. To
accomplish this, create a new class called BouncingSprite
that derives from AutomatedSprite
. BouncingSprite
should do the same thing that
AutomatedSprite
does, with the
exception that it will check during the Update
method to determine whether the
sprite has gone off the edge of the screen. If it has, reverse the
direction of the sprite by multiplying the speed
variable by −1.
Also, make two of the bouncing sprites use the skull image and two of them use the plus image (located with the source code for this chapter in the AnimatedSpritesAnimatedSpritesAnimatedSpritesContentImages directory).
Note that when running this game after making these changes, you’ll have four sprites moving around the screen and the game will exit when any of them collide with the user-controlled sprite. This could cause some issues in testing the game because the sprites may be colliding when the game first loads. Try moving your mouse to a far corner of the screen when loading the game to make sure your user-controlled sprite is out of the way to begin with.
Creating a bouncing sprite should be fairly straightforward at
this point. You’ve already created a sprite that bounces off the edges
of the game window in a previous chapter (more than once if you did
the exercises for the previous chapters). All you’ll need to do is
check in the Update
method whether
the sprite has gone off the edge of the game window and, if it has,
reverse its direction. You’ll then need to update the code in your
SpriteManager
class that creates
the automated sprites to have it create BouncingSprites
with both the skullball and
plus sprites.
Here’s the BouncingSprite
class:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace AnimatedSprites { class BouncingSprite: AutomatedSprite { public BouncingSprite(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed) : base(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed) { } public BouncingSprite(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed, int millisecondsPerFrame) : base(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed, millisecondsPerFrame) { } public override void Update(GameTime gameTime, Rectangle clientBounds) { position += direction; //Reverse direction if hit a side if (position.X > clientBounds.Width - frameSize.X || position.X < 0) speed.X *= −1; if (position.Y > clientBounds.Height - frameSize.Y || position.Y < 0) speed.Y *= −1; base.Update(gameTime, clientBounds); } } }
And you should update the code that creates your automated
sprites in your SpriteManager
class’s LoadContent
method to look
something like this:
//Load several different automated sprites into the list spriteList.Add(new BouncingSprite( Game.Content.Load<Texture2D>(@"Images/skullball"), new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), new Vector2(1,1))); spriteList.Add(new BouncingSprite( Game.Content.Load<Texture2D>(@"Images/plus"), new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0), new Point(6, 4), new Vector2(1,0))); spriteList.Add(new BouncingSprite( Game.Content.Load<Texture2D>(@"Images/plus"), new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0), new Point(6, 4), new Vector2(0,1))); spriteList.Add(new BouncingSprite( Game.Content.Load<Texture2D>(@"Images/skullball"), new Vector2(600, 400), new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), new Vector2(-1,-1)));
What do you use to reference a sound that has been included in an XACT audio file?
To play a sound in an XACT audio file, you reference the sound by its associated cue name.
What are the pros and cons of using the simple sound API available in XNA 4.0 instead of using XACT?
Pros: simple and fast, and supported on the Reach game profile. Cons: no design-time modification of sound properties.
Fact or fiction: the only way to get a soundtrack to loop during gameplay is to manually program the sound in code to play over and over.
Fiction. You can set the looping property of a particular sound in XACT by specifying a certain number of times for the sound to play or by specifying the sound to play in an infinite loop.
Fact or fiction: you can adjust the volume of your sounds using XACT.
Fact. You can adjust the volume, pitch, and other properties of a sound file using XACT.
How do you pause and restart a sound in XNA when using XACT audio files?
If you capture the Cue
object from the GetCue
method
and play the sound from the Cue
object, you can call Pause
,
Stop
, Play
, and other methods on the Cue
object to manipulate playback of
that particular sound.
What was the best-selling video game of 2009?
Call of Duty: Modern Warfare 2 was the best-selling game of 2009, selling just under 12 million copies globally.
Try experimenting with different sounds and sound settings in XNA using XACT. Find a few .wav files and plug them into the game. Experiment with different settings in XACT by grouping multiple sounds in a single cue.
There’s really no right or wrong answer to this exercise. Follow the steps from earlier in the chapter, add some different sounds, and play with the settings in XACT. It doesn’t need to sound pretty; just use this as a chance to become more familiar with XACT and all that it can do.
Developed by Alan Turing, the Turing Test involved having a human interact with a computer and another human, asking questions to determine which was which. The test was designed to determine whether a computer was intelligent. If the interrogator was unable to determine which was the computer and which was the human, the computer was deemed “intelligent.”
Why is artificial intelligence so difficult to perfect?
Because intelligence itself is so difficult to define. It’s something that currently is not truly understood and therefore is ambiguous by nature.
What constitutes irrelevancy for an object in a video game? What should be done with irrelevant objects, and why?
An object is irrelevant if it can no longer affect the game. Irrelevant objects should be deleted because otherwise they will continue to be updated and drawn in each frame, which will negatively affect performance.
If you have a player whose position is stored in a Vector2
object called PlayerPos
and a chasing object whose
position is stored in a Vector2
object called ChasePos
, what
algorithm will cause your chasing object to chase after your player?
if(PlayerPos.X < ChasePos.X) --ChasePos.X; else ++ChasePos.X; if(PlayerPos.Y < ChasePos.Y) --ChasePos.Y; else ++ChasePos.Y;
In the beginning, what was created that made a lot of people very angry and has been widely regarded as a bad move?
According to The Restaurant at the End of the Universe, the second book in Douglas Adams’ hilarious The Hitchhiker’s Guide to the Galaxy series: “In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.”
Take what you’ve learned in this chapter and make yet another type of sprite object, one that moves randomly around the screen. To do this, you’ll want to create a random timer that signifies when the object should change directions. When the timer expires, have the object move in a different direction, and then reset the random timer to a new random time at which the object will again shift its direction.
When dealing with a random object, you need to figure out when it will randomly change direction. Ideally, it will randomly change direction at random intervals. The actual values that are used to determine the thresholds of the random variables can be customized to get the desired functionality, but the underlying code is the same. Here is a randomly moving sprite class:
using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace AnimatedSprites { class RandomSprite : Sprite { SpriteManager spriteManager; //Random variable to determine when to change directions int minChangeTime = 500; int maxChangeTime = 1000; int changeDirectionTimer; Random rnd; public RandomSprite(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed, string collisionCueName, SpriteManager spriteManager, Random rnd) : base(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed, collisionCueName) { this.spriteManager = spriteManager; this.rnd = rnd; ResetTimer(); } public RandomSprite(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed, int millisecondsPerFrame, string collisionCueName, SpriteManager spriteManager, Random rnd) : base(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed, millisecondsPerFrame, collisionCueName) { this.spriteManager = spriteManager; this.rnd = rnd; ResetTimer(); } public override Vector2 direction { get { return speed; } } public override void Update(GameTime gameTime, Rectangle clientBounds) { //Move forward position += speed; Vector2 player = spriteManager.GetPlayerPosition(); //Is it time to change directions? changeDirectionTimer −= gameTime.ElapsedGameTime.Milliseconds; if (changeDirectionTimer < 0) { //Pick a new random direction float Length = speed.Length(); speed = new Vector2((float)rnd.NextDouble() - .5f, (float)rnd.NextDouble() - .5f); speed.Normalize(); speed *= Length; ResetTimer(); } base.Update(gameTime, clientBounds); } private void ResetTimer() { changeDirectionTimer = rnd.Next( minChangeTime, maxChangeTime); } } }
What type of object is used to draw 2D text in XNA?
You need a SpriteFont
object to draw 2D text in XNA.
How is a background image different from an image used to represent a player or object in the game?
It really isn’t any different. The underlying concept is exactly the same: you’re drawing a 2D image on the game window. The background image in this case doesn’t animate, and the file containing the background image contains only that image (in contrast to the player sprites, which are animated; the files used for those objects contain sprite sheets with multiple images forming an animation sequence).
What are game states and how are they used?
Game states represent a way to indicate the current status of the game as a whole or some activity within the game. Game states are used to transition from splash screens to gameplay, from gameplay to end-game screens, and so on.
In the Flight of the Conchords episode “Mugged,” what do the muggers steal from Jemaine?
The muggers steal Jemaine’s camera-phone—which was actually a gift to him from Bret and is also really just Jemaine’s phone glued to a camera.
Change the behavior of the skull power-up (or power-down, if you prefer) to freeze the player for 2 seconds rather than reduce the player’s speed by 50% for 5 seconds. Use different power-up timers for the skull, bolt, and plus sprites.
There really isn’t anything too complicated involved in adding a new power-up (or power-down), now that you’ve fleshed out the core logic. You already have a built-in way to modify the speed of the player via a power-up (the bolt power-up increases the speed by 100%, and the skull currently slows the player by 50%). To freeze the player, all you’ll need to do is reduce the player’s speed to zero while the power-up is in effect. The other thing to think about is that this power-up will last only two seconds, whereas the others lasted five seconds. So, you’ll need to add a new variable to track when this freeze power-up expires.
The modified SpriteManager
class is shown here:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace AnimatedSprites { /// <summary> /// This is a game component that implements IUpdateable. /// </summary> public class SpriteManager : Microsoft.Xna.Framework.DrawableGameComponent { // SpriteBatch for drawing SpriteBatch spriteBatch; // A sprite for the player and a list of automated sprites UserControlledSprite player; List<Sprite> spriteList = new List<Sprite>(); // Variables for spawning new enemies int enemySpawnMinMilliseconds = 1000; int enemySpawnMaxMilliseconds = 2000; int enemyMinSpeed = 2; int enemyMaxSpeed = 6; int nextSpawnTime = 0; // Chance of spawning different enemies int likelihoodAutomated = 75; int likelihoodChasing = 20; int likelihoodEvading = 5; // Scoring int automatedSpritePointValue = 10; int chasingSpritePointValue = 20; int evadingSpritePointValue = 0; // Lives List<AutomatedSprite> livesList = new List<AutomatedSprite>(); //Spawn time variables int nextSpawnTimeChange = 5000; int timeSinceLastSpawnTimeChange = 0; // Powerup stuff int powerUpExpiration = 0; int powerUpFreezeExpiration = 0; public SpriteManager(Game game) : base(game) { // TODO: Construct any child components here } /// <summary> /// Allows the game component to perform any initialization it /// needs to before starting to run. This is where it can query for /// any required services and load content. /// </summary> public override void Initialize() { // Initialize spawn time ResetSpawnTime(); base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(Game.GraphicsDevice); player = new UserControlledSprite( Game.Content.Load<Texture2D>(@"Images/threerings"), new Vector2(Game.Window.ClientBounds.Width / 2, Game.Window.ClientBounds.Height / 2), new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), new Vector2(6, 6)); // Load player lives list for (int i = 0; i < ((Game1)Game).NumberLivesRemaining; ++i) { int offset = 10 + i * 40; livesList.Add(new AutomatedSprite( Game.Content.Load<Texture2D>(@"images hreerings"), new Vector2(offset, 35), new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), Vector2.Zero, null, 0, .5f)); } base.LoadContent(); } /// <summary> /// Allows the game component to update itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { // Time to spawn enemy? nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds; if (nextSpawnTime < 0) { SpawnEnemy(); // Reset spawn timer ResetSpawnTime(); } UpdateSprites(gameTime); // Adjust sprite spawn times AdjustSpawnTimes(gameTime); // Expire Powerups? CheckPowerUpExpiration(gameTime); base.Update(gameTime); } protected void UpdateSprites(GameTime gameTime) { // Update player player.Update(gameTime, Game.Window.ClientBounds); // Update all nonplayer sprites for (int i = 0; i < spriteList.Count; ++i) { Sprite s = spriteList[i]; s.Update(gameTime, Game.Window.ClientBounds); // Check for collisions if (s.collisionRect.Intersects(player.collisionRect)) { // Play collision sound if (s.collisionCueName != null) ((Game1)Game).PlayCue(s.collisionCueName); // If collided with AutomatedSprite // remove a life from the player if (s is AutomatedSprite) { if (livesList.Count > 0) { livesList.RemoveAt(livesList.Count - 1); --((Game1)Game).NumberLivesRemaining; } } else if (s.collisionCueName == "pluscollision") { // Collided with plus - start plus power-up powerUpExpiration = 5000; player.ModifyScale(2); } else if (s.collisionCueName == "skullcollision") { // Collided with skull - start skull power-up powerUpExpiration = 2000; player.ModifySpeed(0f); } else if (s.collisionCueName == "boltcollision") { // Collided with bolt - start bolt power-up powerUpExpiration = 5000; player.ModifySpeed(2); } // Remove collided sprite from the game spriteList.RemoveAt(i); --i; } // Remove object if it is out of bounds if (s.IsOutOfBounds(Game.Window.ClientBounds)) { ((Game1)Game).AddScore(spriteList[i].scoreValue); spriteList.RemoveAt(i); --i; } } // Update lives-list sprites foreach (Sprite sprite in livesList) sprite.Update(gameTime, Game.Window.ClientBounds); } public override void Draw(GameTime gameTime) { spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend); // Draw the player player.Draw(gameTime, spriteBatch); // Draw all sprites foreach (Sprite s in spriteList) s.Draw(gameTime, spriteBatch); // Draw player lives foreach (Sprite sprite in livesList) sprite.Draw(gameTime, spriteBatch); spriteBatch.End(); base.Draw(gameTime); } private void ResetSpawnTime() { // Set the next spawn time for an enemy nextSpawnTime = ((Game1)Game).rnd.Next( enemySpawnMinMilliseconds, enemySpawnMaxMilliseconds); } private void SpawnEnemy() { Vector2 speed = Vector2.Zero; Vector2 position = Vector2.Zero; // Default frame size Point frameSize = new Point(75, 75); // Randomly choose which side of the screen to place enemy, // then randomly create a position along that side of the screen // and randomly choose a speed for the enemy switch (((Game1)Game).rnd.Next(4)) { case 0: // LEFT to RIGHT position = new Vector2( -frameSize.X, ((Game1)Game).rnd.Next(0, Game.GraphicsDevice.PresentationParameters. BackBufferHeight - frameSize.Y)); speed = new Vector2(((Game1)Game).rnd.Next( enemyMinSpeed, enemyMaxSpeed), 0); break; case 1: // RIGHT to LEFT position = new Vector2( Game.GraphicsDevice.PresentationParameters. BackBufferWidth, ((Game1)Game).rnd.Next(0, Game.GraphicsDevice.PresentationParameters. BackBufferHeight - frameSize.Y)); speed = new Vector2(-((Game1)Game).rnd.Next( enemyMinSpeed, enemyMaxSpeed), 0); break; case 2: // BOTTOM to TOP position = new Vector2(((Game1)Game).rnd.Next(0, Game.GraphicsDevice.PresentationParameters. BackBufferWidth - frameSize.X), Game.GraphicsDevice.PresentationParameters. BackBufferHeight); speed = new Vector2(0, -((Game1)Game).rnd.Next(enemyMinSpeed, enemyMaxSpeed)); break; case 3: // TOP to BOTTOM position = new Vector2(((Game1)Game).rnd.Next(0, Game.GraphicsDevice.PresentationParameters.BackBufferWidth - frameSize.X), -frameSize.Y); speed = new Vector2(0, ((Game1)Game).rnd.Next(enemyMinSpeed, enemyMaxSpeed)); break; } // Get random number between 0 and 99 int random = ((Game1)Game).rnd.Next(100); if (random < likelihoodAutomated) { // Create an AutomatedSprite. // Get new random number to determine whether to // create a three-blade or four-blade sprite. if (((Game1)Game).rnd.Next(2) == 0) { // Create a four-blade enemy spriteList.Add( new AutomatedSprite( Game.Content.Load<Texture2D>(@"imagesfourblades"), position, new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), speed, "fourbladescollision", automatedSpritePointValue)); } else { // Create a three-blade enemy spriteList.Add( new AutomatedSprite( Game.Content.Load<Texture2D>(@"images hreeblades"), position, new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), speed, "threebladescollision", automatedSpritePointValue)); } } else if (random < likelihoodAutomated + likelihoodChasing) { // Create a ChasingSprite. // Get new random number to determine whether // to create a skull or a plus sprite. if (((Game1)Game).rnd.Next(2) == 0) { // Create a skull spriteList.Add( new ChasingSprite( Game.Content.Load<Texture2D>(@"imagesskullball"), position, new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), speed, "skullcollision", this, chasingSpritePointValue)); } else { // Create a plus spriteList.Add( new ChasingSprite( Game.Content.Load<Texture2D>(@"imagesplus"), position, new Point(75, 75), 10, new Point(0, 0), new Point(6, 4), speed, "pluscollision", this, chasingSpritePointValue)); } } else { // Create an EvadingSprite spriteList.Add( new EvadingSprite( Game.Content.Load<Texture2D>(@"imagesolt"), position, new Point(75, 75), 10, new Point(0, 0), new Point(6, 8), speed, "boltcollision", this, .75f, 150, evadingSpritePointValue)); } } // Return current position of the player sprite public Vector2 GetPlayerPosition() { return player.GetPosition; } protected void AdjustSpawnTimes(GameTime gameTime) { // If the spawn max time is > 500 milliseconds // decrease the spawn time if it is time to do // so based on the spawn-timer variables if (enemySpawnMaxMilliseconds > 500) { timeSinceLastSpawnTimeChange += gameTime.ElapsedGameTime.Milliseconds; if (timeSinceLastSpawnTimeChange > nextSpawnTimeChange) { timeSinceLastSpawnTimeChange -= nextSpawnTimeChange; if (enemySpawnMaxMilliseconds > 1000) { enemySpawnMaxMilliseconds -= 100; enemySpawnMinMilliseconds -= 100; } else { enemySpawnMaxMilliseconds -= 10; enemySpawnMinMilliseconds -= 10; } } } } protected void CheckPowerUpExpiration(GameTime gameTime) { // Is a power-up active? if (powerUpExpiration > 0) { // Decrement power-up timer powerUpExpiration -= gameTime.ElapsedGameTime.Milliseconds; if (powerUpExpiration <= 0) { // If power-up timer has expired, end all power-ups powerUpExpiration = 0; player.ResetScale(); player.ResetSpeed(); } } // Is a freeze power-up active? if (powerUpFreezeExpiration > 0) { // Decrement power-up timer powerUpFreezeExpiration -= gameTime.ElapsedGameTime.Milliseconds; if (powerUpFreezeExpiration <= 0) { // If power-up timer has expired, end all power-ups powerUpFreezeExpiration = 0; player.ResetSpeed(); } } } } }
Does XNA use a right-handed or left-handed coordinate system?
XNA uses a right-handed coordinate system, which means that if you looked at the origin down the Z axis with positive X moving to your right, the Z axis would be positive in the direction coming toward you.
What makes up a viewing frustum (or field of view) for a camera in XNA 3D?
The viewing frustum is made up of a camera angle and near and far clipping planes.
Culling is the process of not drawing objects that are not facing the camera. For example, you never need to see the inside of a soccer ball when playing a soccer game in XNA, so the processor doesn’t draw that side of the object, which saves valuable processor time.
A vertex declaration lets the graphics device know what type of data you are about to send so it knows how to process that data.
Fact or fiction: there is a difference between applying a rotation multiplied by a translation and applying a translation multiplied by a rotation.
Fact. A rotation *
translation
will cause an object to spin in place,
whereas a translation *
rotation
will cause an object to orbit.
What order of translation and rotation would be needed in order to simulate a planet spinning in place while orbiting the origin?
To spin in place, you first need a rotation. Then to orbit,
you need a translation and a rotation, in that order. So, the
answer is rotation *
translation
*
rotation
.
Fact or fiction: to map the lower-right corner of a texture that is 250×300 pixels in size to a vertex, you should specify the (U, V) coordinate (250, 300).
Fiction. (U, V) coordinates must be between 0 and 1. To specify the upper-left corner of a texture, you use the coordinate (0, 0). To specify the lower-right corner, you use the coordinate (1, 1).
How many vertices are needed to draw three triangles using a triangle list?
A triangle list uses three vertices for each triangle. To draw three triangles, nine vertices are required.
How many vertices are needed to draw three triangles using a triangle strip?
A triangle strip builds a triangle out of the first three vertices and a new triangle with every additional vertex, using the new vertex and the two previous vertices. Five vertices are required to draw three triangles using a triangle strip.
How many polygons were used to draw Marcus in Gears of War?
According to d’Artiste: Character Modeling 2 (Ballistic Publishing, 2010), Marcus took a whopping 15,000 polygons to draw. Crazy to think of how fast the computer and the graphics card are working to bring something that complex to life. Luckily, we don’t have to draw complex models by hand like you did to create the triangle and rectangle in this chapter. In Chapter 10, you’ll see how much easier it is to draw complex objects using models.
Building on the code that you wrote in this chapter, create a six-sided cube with different textures on each side that rotates on multiple axes.
To create the six-sided cube with different textures on each side, first you’ll need
to add five extra images to your project. Then, you’ll have to figure
out the coordinates to draw 12 triangles: 2 for each side of the cube.
Next, create vertices for the sides of the cube in your vertex array,
and then draw each side in your Draw
method. One
thing to be aware of is that you’ll need to begin and end the effect
for each side of the cube because you’ll need to reset the texture for
each side (which must be done before BasicEffect.Begin
is called).
The Game1
class is the only
thing that changes in the solution. It’s listed here:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace _3D_Madness { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; // Game camera Camera camera; // Vertex data VertexPositionTexture[] verts; VertexBuffer vertexBuffer; // Effect BasicEffect effect; // Movement and rotation stuff Matrix worldTranslation = Matrix.Identity; Matrix worldRotation = Matrix.Identity; // Texture info List<Texture2D> textureList = new List<Texture2D>(); public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it /// needs to before starting to run. This is where it can query for /// any required services and load any content. /// </summary> protected override void Initialize() { // Initialize camera camera = new Camera(this, new Vector3(0, 0, 5), Vector3.Zero, Vector3.Up); Components.Add(camera); base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); //initialize vertices verts = new VertexPositionTexture[24]; //FRONT verts[0] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(0, 0)); verts[1] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(1, 0)); verts[2] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(0, 1)); verts[3] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(1, 1)); //BACK verts[4] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(0, 0)); verts[5] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(1, 0)); verts[6] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(0, 1)); verts[7] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(1, 1)); //LEFT verts[8] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(0, 0)); verts[9] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(1, 0)); verts[10] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(0, 1)); verts[11] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(1, 1)); //RIGHT verts[12] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(0, 0)); verts[13] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(1, 0)); verts[14] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(0, 1)); verts[15] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(1, 1)); //TOP verts[16] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(0, 0)); verts[17] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(1, 0)); verts[18] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(0, 1)); verts[19] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(1, 1)); //BOTTOM verts[20] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(0, 0)); verts[21] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(1, 0)); verts[22] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(0, 1)); verts[23] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(1, 1)); // Set vertex data in VertexBuffer vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), verts.Length, BufferUsage.None); vertexBuffer.SetData(verts); // Initialize the BasicEffect effect = new BasicEffect(GraphicsDevice); //load all textures textureList.Add(Content.Load<Texture2D>(@"TexturesTrees")); textureList.Add(Content.Load<Texture2D>(@"Textures 1")); textureList.Add(Content.Load<Texture2D>(@"Textures 2")); textureList.Add(Content.Load<Texture2D>(@"Textures 3")); textureList.Add(Content.Load<Texture2D>(@"Textures 4")); textureList.Add(Content.Load<Texture2D>(@"Textures 5")); } /// <summary> /// UnloadContent will be called once per game and is the /// place to unload all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non-ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // Translation KeyboardState keyboardState = Keyboard.GetState(); if (keyboardState.IsKeyDown(Keys.Left)) worldTranslation *= Matrix.CreateTranslation(-.01f, 0, 0); if (keyboardState.IsKeyDown(Keys.Right)) worldTranslation *= Matrix.CreateTranslation(.01f, 0, 0); // Rotation worldRotation *= Matrix.CreateFromYawPitchRoll( MathHelper.PiOver4 / 60, MathHelper.PiOver4 / 360, MathHelper.PiOver4 / 180); base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Set the vertex buffer on the GraphicsDevice GraphicsDevice.SetVertexBuffer(vertexBuffer); //Set object and camera info effect.World = worldRotation * worldTranslation * worldRotation; effect.View = camera.view; effect.Projection = camera.projection; effect.TextureEnabled = true; // Draw front effect.Texture = textureList[0]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 0, 2); } //draw back effect.Texture = textureList[1]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 4, 2); } //draw left effect.Texture = textureList[2]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 8, 2); } //draw right effect.Texture = textureList[3]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 12, 2); } //draw top effect.Texture = textureList[4]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 16, 2); } //draw bottom effect.Texture = textureList[5]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, 20, 2); } base.Draw(gameTime); } } }
What model format(s) are supported in XNA?
XNA supports .x and .fbx model files.
Why use a model when you can just draw things on your own?
Models allow you to build a model or design in a third-party tool specifically designed for artistically modeling and molding three-dimensional objects. It would be nearly impossible to develop objects by hand in XNA 3D using primitives and attain the same level of detail and complexity that is achievable using a model.
What type of effect are models loaded with by default when they’re loaded into XNA?
By default, models in XNA use BasicEffect
s.
Fact or fiction: if your model has separate texture files associated with it, but those files aren’t in the location specified by the model file, your game will crash when it tries to load the model.
Fiction. Your game would not compile if textures were missing. The content pipeline would throw a compilation error.
What number comes next in the sequence {4, 8, 15, 16, 23}?
42. These are the numbers that haunted Hurley in one of the greatest television series of all time, ABC’s Lost.
Take the code from this chapter and create a new subclass of
BasicModel
in which the ship moves
back and forth between (0, 0, 0) and (0, 0, −400). Make the ship turn
appropriately to always face the direction in which it is
going.
There are numerous solutions that will give you the effect
described here. The following solution uses a variable to indicate how
far the ship can go in the background and a direction Vector3
variable to indicate the
ship’s current direction. When the ship reaches a point where it must
turn around, the Direction
’s Z
value is multiplied by −1 and the ship is rotated on a 180 degree yaw
to make it face the direction it is heading. The code for a subclass
of BasicModel
that solves this
exercise is shown here (note that you’ll have to create this class and
then also modify the ModelManager
to create an object of this type rather than the SpinningEnemy
type):
using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace _3D_Game { class FlyingShip : BasicModel { Matrix rotation = Matrix.CreateRotationY(MathHelper.Pi); Matrix translation = Matrix.Identity; float maxDistance = −400; Vector3 direction = new Vector3(0, 0, −1); public FlyingShip(Model m) : base(m) { } public override void Update() { //if the object has traveled past the max distance //or in front of the origin, reverse direction //and rotate ship 180 degrees if (translation.Translation.Z < maxDistance || translation.Translation.Z > 0) { direction.Z *= −1; rotation *= Matrix.CreateRotationY(MathHelper.Pi); } translation *= Matrix.CreateTranslation(direction); } public override Matrix GetWorld() { return world * rotation * translation; } } }
When performing a yaw rotation with a camera, what camera vector(s) rotate(s)? What axis would you rotate on?
In a yaw, the only vector that changes is the camera direction. You rotate the direction vector around the camera’s up vector.
When performing a roll rotation with a camera, what camera vector(s) rotate(s)? What axis would you rotate on?
In a roll, the only vector that changes is the camera’s up vector. You rotate the up vector around the camera’s direction vector.
When performing a pitch rotation with a camera, what camera vector(s) rotate(s)? What axis would you rotate on?
In a pitch, the direction vector always changes and, depending on whether you’re creating a land-based camera or a flight-simulator camera, you may also rotate the up vector. You rotate both of these vectors around the cross product of the camera’s up and direction vectors.
What famous holiday includes an event titled the “Airing of Grievances”?
Festivus (a holiday invented by Frank Costanza on the greatest show of all time, Seinfeld) includes the “Airing of Grievances,” which takes place immediately after the Festivus feast and consists of all participants letting everybody know how much they have disappointed you that year.
Remember that to move a 3D camera forward, you use the following code:
cameraPosition += cameraDirection * speed;
There is a small problem with this method, however, when it’s
applied to land-based cameras. Essentially, to eliminate the ability
to “fly” when looking up, you remove the Y component of the cameraDirection
vector prior to moving the
camera with this line of code. This causes your camera to stay at the
same Y value, which keeps the camera on the ground.
However, consequently the higher you pitch your camera, the
slower you end up moving. For example, if your cameraDirection
vector was (10, 2, 0) when
you removed the Y component, you would end up with the vector (10, 0,
0) and you’d move at that speed. If your camera was pitched at a
larger angle and your cameraDirection
vector was (2, 10, 0), the
resulting vector after removing the Y component would be (2, 0, 0) and
you’d move forward at that speed.
Convert your 3D Flying Camera solution to a land-based camera and solve this problem so that when moving forward and backward your camera moves at the same speed, regardless of the pitch angle. Use the code you created in the first half of this chapter.
Hint: remember that Vector3.Normalize
will take any Vector3
and give it a magnitude or length of
1.
The solution to this problem is fairly straightforward. First,
you remove the Y component of the direction vector, and then you
normalize the resulting vector, which gives the vector a magnitude (or
length) of 1. Once you do this, you can multiply the vector by the
speed of the camera and add it to your camera position. The code that
moves the camera forward and backward is found in the Update
method of the Camera
class. The solution to the problem
affects only that code and is shown here:
//Remove the Y component of the camera direction Vector3 movementDirection = cameraDirection; movementDirection.Y = 0; //Normalize the vector to ensure constant speed movementDirection.Normalize(); // Move forward/backward if (Keyboard.GetState().IsKeyDown(Keys.W)) cameraPosition += movementDirection * speed; if (Keyboard.GetState().IsKeyDown(Keys.S)) cameraPosition −= movementDirection * speed;
When firing a shot in a 3D (or 2D, for that matter) game, how do you determine the direction of the shot?
Typically, the thing that’s firing a shot (a camera, a gun, etc.) has a direction of its own. When firing a shot, you give the bullet or projectile the same direction vector as the item from which it emanates.
Fact or fiction: every model has a BoundingSphere
object that surrounds the entire model and can be
used for collision detection.
Fiction. The BoundingSphere
object belongs to a
ModelMesh
object. Every
Model
has one or more ModelMesh
objects. The BoundingSphere
therefore may cover the
entire model, but a Model
may
also have several meshes, and in that case, the Model
will have multiple BoundingSphere
objects that each
surround portions of the Model
.
When using BoundingSphere
s associated with a moving
model for collision detection, what must be done to the BoundingSphere
in order to accurately
detect collisions?
BoundingSphere
s do not
automatically move, rotate, and scale with the model that owns
them. You need to apply the movement, rotation, and scale matrices
to the BoundingSphere
before
using them for collision detection.
What is the difference between drawing 2D images on screen in a 3D game and drawing 2D images on the screen in a 2D game?
Nothing. Drawing in 2D is the same, regardless of whether there are also 3D graphics in the game.
Why does Kramer’s advice to Elaine regarding his karate class and the power of the inner katra backfire on Elaine?
After Kramer encourages Elaine to run the J. Peterman catalog by relaying stories of his dominance of the karate dojo, Elaine gains new perspective and excitement for the task ahead. But everything falls apart when she finds out that Kramer is dominating the dojo because his peers are 8-year-old children:
Elaine: Kramer!
Kramer: Oh, hey.
Elaine: What are you doing?
Kramer: Oh, well, I-I-I’m dominating.
Elaine: You never said you were fighting children.
Kramer: Well, it’s not the size of the opponent, Elaine, it’s, uh, the ferocity.
Elaine: This is what you used to build me up? This is where you got all that stupid katra stuff?
Kramer: No, no. That’s from, uh, Star Trek III…The Search for Spock.
Elaine: Search…for Spock?!
Kramer: Yeah, I know Jerry will tell you that The Wrath of Khan is the better picture, but for me, I always….
Elaine: (pushes him) You doofus!
To familiarize yourself further with what was covered in this chapter, customize the shot firing mechanism by modifying the code to do the following:
Slow the shots down by 50%.
Cut the shot delay in half (i.e., make shots fire twice as often when holding the space bar continuously).
Every time a shot is fired, fire three shots in a spread (i.e., one shot down the center and two other shots, one to the left and one to the right).
Well, the first two problems here are easy: by changing the initial values for the variables representing the shot speed and the shot delay, you can solve each of those problems with minimal coding. To fire three shots in a spread, you’ll have to find the code where a single shot is fired and add two more shots to the model manager (one to the right of the original shot and one to the left).
The Game1
class is the only
one that needs modification. Here is a sample solution:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace _3D_Game { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; public Camera camera { get; protected set; } ModelManager modelManager; //Randomness public Random rnd { get; protected set; } //Shots float shotSpeed = 5; int shotDelay = 150; int shotCountdown = 0; //Crosshair Texture2D crosshairTexture; //Audio AudioEngine audioEngine; WaveBank waveBank; SoundBank soundBank; Cue trackCue; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferHeight = 1024; #if !DEBUG graphics.IsFullScreen = true; #endif rnd = new Random(); } protected override void Initialize() { //Initialize camera camera = new Camera(this, new Vector3(0, 0, 50), Vector3.Zero, Vector3.Up); Components.Add(camera); //Initialize model manager modelManager = new ModelManager(this); Components.Add(modelManager); base.Initialize(); } protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); //Load crosshair crosshairTexture = Content.Load<Texture2D>(@"textures crosshair"); // Load sounds and play initial sounds audioEngine = new AudioEngine( @"ContentAudioGameAudio.xgs"); waveBank = new WaveBank(audioEngine, @"ContentAudioWave Bank.xwb"); soundBank = new SoundBank(audioEngine, @"ContentAudioSound Bank.xsb"); trackCue = soundBank.GetCue("Tracks"); trackCue.Play(); } protected override void UnloadContent() { // TODO: Unload any non-ContentManager content here } 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); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Black); // TODO: Add your drawing code here base.Draw(gameTime); //Draw 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(); } protected void FireShots(GameTime gameTime) { if (shotCountdown <= 0) { // Did player press space bar or left mouse button? if (Keyboard.GetState().IsKeyDown(Keys.Space) || Mouse.GetState().LeftButton == ButtonState.Pressed) { // Add a shot to the model manager modelManager.AddShot( camera.cameraPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); //Add shot in spread to the right Vector3 initialPosition = camera.cameraPosition + Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5; modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); //Add shot in spread to the left initialPosition = camera.cameraPosition - Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5; modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); // Play shot audio PlayCue("Shot"); // Reset the shot countdown shotCountdown = shotDelay; } } else shotCountdown −= gameTime.ElapsedGameTime.Milliseconds; } public void PlayCue(string cue) { soundBank.PlayCue(cue); } } }
In HLSL, how can you access the first element in a float4
object?
If you want to access the first element in a float4
object called color
, you can use array notation
(color[0]
), or you can use the
namespaces for color and position (color.r
or color.x
).
What is swizzling?
The term swizzling refers to accessing multiple elements of a float4
or similar datatype at the same
time by using two or more elements from the color or position
namespaces (e.g., color.rb
or
color.xyz
).
In HLSL, how do you specify which vertex and pixel shader versions to use?
In the pass
block of the
technique for an HLSL effect file, you specify a VertexShader
and/or a PixelShader
by providing the compile
keyword followed by a shader
version. For vertex shaders, you use vs_2_0
syntax, and for pixel shaders,
you use ps_2_0
syntax.
What does HLSL do for you that you can’t accomplish without it?
HLSL allows developers to access hardware functions that aren’t available via the XNA Framework. The reason: graphics hardware has become more and more complex, and if the XNA Framework were expanded to handle all capabilities of graphics cards, the framework would be enormous. Instead, HLSL works with XNA and allows you to write code for the graphics card itself.
How do you multiply two matrices together in HLSL?
The mul
function in HLSL
will multiply together two matrices.
What is the role of a semantic in HLSL?
A semantic marks a variable as being used for a certain purpose. For input parameters, the semantic means that the parameter will automatically be given a value specified by the semantic. For output parameters, it is a way to flag certain variables as containing certain information that is required for processing that takes place after the shader is finished executing.
Who burninates the countryside, burninates the peasants, burninates all the people, and their thatch-roofed cottages?
Trogdor, the man…er…dragon man…er…the dragon, of course.
Take the code you built in this chapter and draw a six-sided cube using the trees image provided as the texture for each side of the cube. One each side of the cube, use one of the four texture effects you built in this chapter (normal texture, burred texture, negative texture, grayscale texture). Use each of the four effects at least once on the cube.
This exercise is very similar to the one from Chapter 9 in which you built a six-sided cube with different textures on each side. The difference here is that you’ll be applying the same texture to each side of the cube and then applying different HLSL effects to those sides.
First, create the different effect files as shown in this chapter, and then use something similar to the following code to create the cube and apply the effects:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace _3D_Madness { /// <summary> /// This is the main type for your game. /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; // Game camera Camera camera; // Vertex data VertexPositionTexture[] verts; VertexBuffer vertexBuffer; // Effect Effect normalEffect; Effect blurEffect; Effect negativeEffect; Effect grayscaleEffect; // Movement and rotation stuff Matrix worldTranslation = Matrix.Identity; Matrix worldRotation = Matrix.Identity; // Texture info Texture2D texture; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it /// needs to before starting to run. This is where it can query for /// any required services and load content. /// </summary> protected override void Initialize() { // Initialize camera camera = new Camera(this, new Vector3(0, 0, 5), Vector3.Zero, Vector3.Up); Components.Add(camera); base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); //initialize vertices verts = new VertexPositionTexture[24]; //FRONT verts[0] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(0, 0)); verts[1] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(1, 0)); verts[2] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(0, 1)); verts[3] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(1, 1)); //BACK verts[4] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(0, 0)); verts[5] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(1, 0)); verts[6] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(0, 1)); verts[7] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(1, 1)); //LEFT verts[8] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(0, 0)); verts[9] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(1, 0)); verts[10] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(0, 1)); verts[11] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(1, 1)); //RIGHT verts[12] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(0, 0)); verts[13] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(1, 0)); verts[14] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(0, 1)); verts[15] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(1, 1)); //TOP verts[16] = new VertexPositionTexture( new Vector3(-1, 1, -1), new Vector2(0, 0)); verts[17] = new VertexPositionTexture( new Vector3(1, 1, -1), new Vector2(1, 0)); verts[18] = new VertexPositionTexture( new Vector3(-1, 1, 1), new Vector2(0, 1)); verts[19] = new VertexPositionTexture( new Vector3(1, 1, 1), new Vector2(1, 1)); //BOTTOM verts[20] = new VertexPositionTexture( new Vector3(-1, -1, 1), new Vector2(0, 0)); verts[21] = new VertexPositionTexture( new Vector3(1, -1, 1), new Vector2(1, 0)); verts[22] = new VertexPositionTexture( new Vector3(-1, -1, -1), new Vector2(0, 1)); verts[23] = new VertexPositionTexture( new Vector3(1, -1, -1), new Vector2(1, 1)); // Set vertex data in VertexBuffer vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), verts.Length, BufferUsage.None); vertexBuffer.SetData(verts); //Load effect normalEffect = Content.Load<Effect>(@"effectsRed"); grayscaleEffect = Content.Load<Effect>(@"effectsGrayscale"); negativeEffect = Content.Load<Effect>(@"effectsNegative"); blurEffect = Content.Load<Effect>(@"effectsBlur"); // Load texture texture = Content.Load<Texture2D>(@"Textures rees"); } /// <summary> /// UnloadContent will be called once per game and is /// the place to unload all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non-ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // Translation KeyboardState keyboardState = Keyboard.GetState(); if (keyboardState.IsKeyDown(Keys.Left)) worldTranslation *= Matrix.CreateTranslation(-.01f, 0, 0); if (keyboardState.IsKeyDown(Keys.Right)) worldTranslation *= Matrix.CreateTranslation(.01f, 0, 0); // Rotation worldRotation *= Matrix.CreateFromYawPitchRoll( MathHelper.PiOver4 / 60, 0, 0); base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values. /// </param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Set the vertex buffer on the GraphicsDevice GraphicsDevice.SetVertexBuffer(vertexBuffer); //Draw front DrawVerts(normalEffect, 0, 2); //Draw back DrawVerts(blurEffect, 4, 2); //Draw left DrawVerts(grayscaleEffect, 8, 2); //Draw right DrawVerts(negativeEffect, 12, 2); //Draw top DrawVerts(blurEffect, 16, 2); //Draw bottom DrawVerts(grayscaleEffect, 20, 2); base.Draw(gameTime); } protected void DrawVerts(Effect effect, int start, int end) { effect.CurrentTechnique = effect.Techniques["Textured"]; Matrix world = worldRotation * worldTranslation; effect.Parameters["xWorldViewProjection"].SetValue( world * camera.view * camera.projection); effect.Parameters["xColoredTexture"].SetValue(texture); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionTexture> (PrimitiveType.TriangleStrip, verts, start, end); } } } }
A particle engine is a mechanism that manipulates, moves, adds, removes, and draws particles to create a particle effect.
Why were there two textures used for the particles in your explosion? What was the purpose of each?
The first texture you added to the project (particle.png) represents the shape of each particle. It is simply a shaded, round circle, all white, with a transparent background. The second texture (particleColors.png) is used to get random colors with which to color each particle. The same technique was used with the stars using the particle.png file for the shape and the stars.png file for the colors.
What are texture (U, V) coordinates?
(U, V) coordinates map texture sizes into a coordinate system that ranges from 0 to 1 horizontally (U) and 0 to 1 vertically (V).
According to Napoleon Dynamite’s Uncle Rico, how far could Uncle Rico throw a “pigskin” back in 1982?
In the movie Napoleon Dynamite, Uncle Rico often reminisces of the good ol’ days in ’82:
Uncle Rico: Back in ’82, I used to be able to throw a pigskin a quarter mile.
Kip: Are you serious?
Uncle Rico: I’m dead serious.
Create a multishot power-up that, when active, will fire four shots instead of one. Instead of shooting one shot in the center of the camera, when multishot is active, shoot one shot from above and right of the camera, one from above and left, one from below and right, and one from below and left.
When the player shoots three ships in a row, the game will randomly choose which power-up to activate (rapid fire or multishot).
You have all the code fleshed out to create a power-up. Now
you’ll need to take that code and add a new multishot power-up. Start
with adding a new value to the PowerUps
enum
to represent multishot mode.
Once that’s done, there are really only two other steps: add code when a power-up is triggered that randomly picks the multishot or rapid fire mode, and add the code to fire multiple shots in multishot mode.
The difficult part will be in the FireShots
method of the Game1
class, where you’ll need to add the
code for multiple shots. Here is one possible solution for that part
of the problem:
protected void FireShots(GameTime gameTime) { if (shotCountdown <= 0) { // Did player press space bar or left mouse button? if (Keyboard.GetState().IsKeyDown(Keys.Space) || Mouse.GetState().LeftButton == ButtonState.Pressed) { if (currentPowerUp != PowerUps.MULTI_SHOT) { //Normal mode - fire one shot // Add a shot to the model manager modelManager.AddShot( camera.cameraPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); } else { //Multi-shot mode! //Add shot in spread to the top right Vector3 initialPosition = camera.cameraPosition + Vector3.Cross(camera.GetCameraDirection, camera. cameraUp) * 5 + (camera.cameraUp * 5); modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); //Add shot in spread to the bottom right initialPosition = camera.cameraPosition + Vector3.Cross(camera.GetCameraDirection, camera. cameraUp) * 5 - (camera.cameraUp * 5); modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); //Add shot in spread top left initialPosition = camera.cameraPosition − Vector3.Cross(camera.GetCameraDirection, camera. cameraUp) * 5 + (camera.cameraUp * 5); modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); //Add shot in spread bottom left initialPosition = camera.cameraPosition − Vector3.Cross(camera.GetCameraDirection, camera. cameraUp) * 5 − (camera.cameraUp * 5); modelManager.AddShot( initialPosition + new Vector3(0, −5, 0), camera.GetCameraDirection * shotSpeed); } // Play shot audio PlayCue("Shot"); // Reset the shot countdown shotCountdown = shotDelay; } } else shotCountdown −= gameTime.ElapsedGameTime.Milliseconds; }
What piece of information does a PC use to identify a specific Xbox 360 machine?
XNA uses a connection key to identify an Xbox 360 machine on a PC.
Fact or fiction: to debug a project that has been deployed on an Xbox 360, you have to load the code in the Xbox 360 code editor and place a breakpoint within the code on the Xbox 360 machine.
Fiction. To debug projects that are deployed on an Xbox 360, place a breakpoint in the code on the PC used to deploy the project. If you then start the project in debug mode, it will run on the Xbox 360 and allow you to debug on the connected PC.
Fact or fiction: if you’ve created a Windows game project and you want to deploy that project to your Xbox 360, you need to create a new project in order to do so.
Fact. Creating a Windows project allows you to run your game on Windows only, and creating an Xbox 360 project allows you to run your game on an Xbox 360 only. To facilitate multiplatform development, you can create a project for one platform and then create a copy of it for another platform and share files between the two.
What is a preprocessor directive?
Preprocessor directives give developers a way to write code intended for the preprocessor rather than the compiler. Developers can perform logic that affects what code is compiled and how it is compiled using these directives.
What does the following code do in a Windows project?
#if (XBOX360) int A = 5; int B = 4; int C = A − B; #endif
Because the XBOX360
symbol is not defined for a Windows project, this code not only
does nothing, but it will not even compile in the game. The end
result of the project will be exactly the same as if the code did
not exist.
What does “serenity now” lead to?
According to Lloyd Braun, a childhood neighbor of George Costanza, serenity now leads to insanity later.
What are the three types of developer accounts you can create for development on Windows Phone 7?
You can register for an account as a business, an individual, or a student.
What software do you use to unlock your Windows Phone 7 device?
You use the Microsoft Zune software to unlock your Windows Phone 7 as well as to connect to the device through Visual Studio.
How do you read data from the Windows Phone 7 accelerometer?
You handle the ReadingChanged
event on
the accelerometer and capture the X, Y, and/or Z values in that
method’s AccelerometerReadingEventArgs
parameter.
What is the default screen resolution and screen rotation of a Windows Phone 7 game?
The default screen rotation is
LandscapeLeft
, and the resolution is
800×480.
What are the possible states of a TouchLocation
object?
Invalid
(indicating an error occurred),
Moved
(indicating a single touch has changed
position), Pressed
(indicating a new touch
location was pressed), and Released
(indicating
that the touch location was released).
Why does Brody the Bootlegger get angry with Jerry Seinfeld during the movie Death Blow?
Because Jerry made a comment about the large bag of candy that Brody was chowing down on all by himself:
Kramer: There’s Brody. Brody! Over here…
Brody: Hey, Kramer. And you must be Jerry. Thanks for the ticket.
Jerry: That’s quite a feed bag you’re workin’ on there.
Brody: It’s for all of us. Is there a problem?
Kramer: Brody, c’mon. He’s just kidding. He’s a joke maker. Tell him, Jerry.
Jerry: I’m a joke maker.
If you create a two-player split screen, what should you use for the camera’s aspect ratio to ensure that your graphics don’t look squished?
Instead of using the width and height of the game window for your aspect ratio, you should use the width and height of the viewport for that split-screen view.
Fact or fiction: networked games in XNA use a networking API that works on the PC and Xbox 360 but is different on the Zune.
Fiction. The networking API in XNA is compatible with all three platforms (PC, Xbox 360, and Zune)—although each platform can communicate only with devices of its own type.
What’s the difference between a peer-to-peer and a client/server network architecture?
Peer-to-peer networks have no server, and all machines send data to all other machines in the network. Client/server networks have a server and one or more clients. All clients send data to the server, and the server broadcasts all messages to all clients.
Which network type (peer-to-peer or client/server) is better?
That totally depends on the type of game you’re creating. You’ll need to consider the number of players involved as well as how much information needs to be updated throughout the game.
What will happen if you don’t call NetworkSession.Update
in your game?
The NetworkSession
.Update
call updates your session and
pumps all network messages through the session. If you don’t call
this method, the machines on the network will not be able to
communicate and sync up in order for the game to be played.
How do you force a user to sign in using the gamer services sign-in windows?
Calling Guide.ShowSignIn
makes the game window render a series of gamer services windows
that allow players to sign into their online gamertags or local
accounts.
How do you send a message to another player in a networked XNA game?
You’ll first need to write the data to a PacketWriter
object using the PacketWriter.Write
method. You’ll then
send the data via the local gamer’s SendData
method.
How do you read a message from another player?
You use a PacketReader
object in the local gamer’s ReceiveData
method to pull the packet from the network. You then use
different methods of the Packet
Reader
to pull out different types
of data (for example, ReadInt32
).
When receiving a network message in XNA, how do you know
what type of data is going to be read from the PacketReader
and what that data
means?
You’ll typically want to create an enum
indicating the type of each
message. You’ll then send that enum
value as the first item in every
packet. When reading packets, you’ll read the message type and
perform the action appropriate for that message type.
What, according to Harry Dunne, is worse than his roommate, Lloyd Christmas, getting robbed by an old lady?
In the movie Dumb and Dumber—one of the greatest films of our time—Harry and Lloyd go from bad to worse when Harry’s pet parakeet comes down with a sudden illness:
Lloyd: I got robbed by a sweet old lady on a motorized cart. I didn’t even see it coming.
Harry: Oh, no, no.
Lloyd: Come on, Harry.
Harry: It gets worse. My parakeet, Petey.
Lloyd: Yeah?
Harry: He’s dead.
Lloyd: Oh, man, I’m sorry. What happened?
Harry: His head fell off.
Lloyd: His head fell off?
Harry: Yeah. He was pretty old.
3.143.5.15