Subscribe

RSS Feed (xml)

Powered By

Powered by Blogger

Google
 
xnahelp.blogspot.com

Kamis, 03 April 2008

Creating a Stationary Camera

Now that we know how to utilize our input, we can get working on implementing our
stationary camera. We actually have most of this done, but we need to add pitching as
well as the yaw we already have. One use for a stationary camera is to look at an object
and follow it by rotating as needed. This is commonly used in racing game replay mode.
Before we dig into the camera changes, though, let’s add a few more rectangles to our
world. We can do this by adding the following code to the end of our demo’s Update
method:
world = Matrix.CreateTranslation(new Vector3(8.0f, 0, -10.0f));
DrawRectangle(ref world);
world = Matrix.CreateTranslation(new Vector3(8.0f, 0, -6.0f));
DrawRectangle(ref world);
world = Matrix.CreateRotationY(Matrix.CreateTranslation(new Vector3(3.0f, 0, 10.0f));
DrawRectangle(ref world);
We should also change our cull mode to None so that as we rotate around that we will
always see our rectangles. We can do that by calling the following code at the top of our
game’s Draw method:
graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
To get our camera updated we need to modify our camera class a little bit. First we need
to declare a private member field as follows:
private float cameraPitch = 0.0f;
Now we can modify the Update method to set our camera pitch. Remember, pitching
refers to rotating around the x axis. To calculate this we simply take the code we did for
calculating the yaw and replace our reference to the y axis with the x axis. The following
is the code to check our keyboard and game pad:
if (input.KeyboardState.IsKeyDown(Keys.Down) ||
(input.GamePads[0].ThumbSticks.Right.Y < 0))
{
cameraPitch -= (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Up) ||
(input.GamePads[0].ThumbSticks.Right.Y > 0))
{
cameraPitch += (spinRate * timeDelta);
}
100 CHAPTER 5 Input Devices and Cameras
No surprises there, and we need to do the same thing with our mouse code. Inside of the
#if !XBOX360 compilation directive we already have we can add the following code:
if ((input.PreviousMouseState.Y > input.MouseState.Y) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraPitch += (spinRate * timeDelta);
}
else if ((input.PreviousMouseState.Y < input.MouseState.Y) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraPitch -= (spinRate * timeDelta);
}
We want to clamp our values so we do not rotate over 90 degrees in either direction:
if (cameraPitch > 89)
cameraPitch = 89;
if (cameraPitch < -89)
cameraPitch = -89;
Finally, we need to update our rotation matrix to include our pitch value. Here is the
updated calculation:
Matrix rotationMatrix;
Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);
//add in pitch to the rotation
rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch)) *
rotationMatrix;
The last statement is the only thing we added. We just added our pitch to the rotation
matrix that was already being used to transform our camera. The full Update listing can
be found in Listing 5.1.
LISTING 5.1 Our stationary camera’ s Update method
public override void Update(GameTime gameTime)
{
float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (input.KeyboardState.IsKeyDown(Keys.Left) ||
(input.GamePads[0].ThumbSticks.Right.X < 0))
{
cameraYaw += (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Right) ||
(input.GamePads[0].ThumbSticks.Right.X > 0))
Creating a Stationary Camera 101
5
{
cameraYaw -= (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Down) ||
(input.GamePads[0].ThumbSticks.Right.Y < 0))
{
cameraPitch -= (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Up) ||
(input.GamePads[0].ThumbSticks.Right.Y > 0))
{
cameraPitch += (spinRate * timeDelta);
}
#if !XBOX360
if ((input.PreviousMouseState.X > input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw += (spinRate * timeDelta);
}
else if ((input.PreviousMouseState.X < input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw -= (spinRate * timeDelta);
}
if ((input.PreviousMouseState.Y > input.MouseState.Y) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraPitch += (spinRate * timeDelta);
}
else if ((input.PreviousMouseState.Y < input.MouseState.Y) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraPitch -= (spinRate * timeDelta);
}
#endif
//reset camera angle if needed
if (cameraYaw > 360)
cameraYaw -= 360;
else if (cameraYaw < 0)
102 CHAPTER 5 Input Devices and Cameras
LISTING 5.1 Continued
cameraYaw += 360;
//keep camera from rotating a full 90 degrees in either direction
if (cameraPitch > 89)
cameraPitch = 89;
if (cameraPitch < -89)
cameraPitch = -89;
Matrix rotationMatrix;
Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw),
out rotationMatrix);
//add in pitch to the rotation
rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraPitch))
* rotationMatrix;
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);
Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,
out view);
base.Update(gameTime);
}

Read More......

Working with mouse Devices

This input device is only available for Windows, so if we are deploying our game for the
Xbox 360 we will need to put the XBOX360 compilation directive check we learned about
in Chapter 2 around any code that references the mouse as an input device. So we will
create a private member field with this preprocessor check inside of our InputHandler
class. We need to set up a private member field to hold our previous mouse state and
another one to hold our current mouse state:
#if !XBOX360
private MouseState mouseState;
private MouseState prevMouseState;
#endif
Then in our constructor we tell XNA that we want the mouse icon visible in our window
and we store our current mouse state:
#if !XBOX360
Game.IsMouseVisible = true;
prevMouseState = Mouse.GetState();
#endif
In our Update method of the input handler game component we need to set the previous
state to what our current state is and then reset our current state as follows:
#if !XBOX360
prevMouseState = mouseState;
mouseState = Mouse.GetState();
#endif
98 CHAPTER 5 Input Devices and Cameras
Now we need to expose these internal fields so our camera (and any other) object can get
their values. First we need to add the properties to our interface as follows:
#if !XBOX360
MouseState MouseState { get; }
MouseState PreviousMouseState { get; }
#endif
Now we can implement those properties in our class:
#if !XBOX360
public MouseState MouseState
{
get { return(mouseState); }
}
public MouseState PreviousMouseState
{
get { return(prevMouseState); }
}
#endif
In our camera’s Update method we want to get the latest state of our mouse and compare
the current X value to the previous X value to determine if we moved the mouse left or
right. We also want to check if the left mouse button is pushed before updating our
cameraYaw variable. Of course, all of this is wrapped in our compilation preprocessor
condition as follows:
#if !XBOX360
if ((input.PreviousMouseState.X > input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw += (spinRate * timeDelta);
}
else if ((input.PreviousMouseState.X < input.MouseState.X) &&
(input.MouseState.LeftButton == ButtonState.Pressed))
{
cameraYaw -= (spinRate * timeDelta);
}
#endif
We can compile and run the code and test the latest functionality on Windows. If the
preprocessor checks are in place correctly, we should be able to deploy this demo to the
Xbox 360 as well, although it will not do anything different than it did before we added
the mouse support.

Read More......

Working with gamepad Devices

The Microsoft Xbox 360 wired controller works on the PC. XNA provides us with helper
classes that make it very easy to determine the state of our game pad. The template
already provided one call to the game pad helper class. This call is also in the Update
method. Let’s take a look at what is provided for us already.
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
The template is calling the built-in XNA class GamePad and calling its GetState method
passing in which player’s controller they want to check. The template then checks the
Back button on that controller to see if it has been pressed. If the controller’s Back button
has been pressed, the game exits. Now, that was pretty straightforward. To be consistent
we can use our input class to check for the condition.
Before we can do that, we need to update our interface and add the appropriate property
as well as actually getting the game pad state just like we did for our keyboard. Let’s jump
to our input handler code and do some of these things. We can start by adding a property
to get to our list of game pads in our interface:
GamePadState[] GamePads { get; }
Now we can create the member field and property to get that field like the following code:
private GamePadState[] gamePads = new GamePadState[4];
public GamePadState[] GamePads
{
get { return(gamePads); }
}
Working with Input Devices 95
5
We need to initialize each game pad state and can do that in the Update method of the
input handler object:
gamePads[0] = GamePad.GetState(PlayerIndex.One);
gamePads[1] = GamePad.GetState(PlayerIndex.Two);
gamePads[2] = GamePad.GetState(PlayerIndex.Three);
gamePads[3] = GamePad.GetState(PlayerIndex.Four);
Now, let’s remove the code that checks to see if the Back button is pressed on player one’s
game pad from our demo. We can add this code in the Update method of our
InputHandler game component to get the same effect:
if (gamePads[0].Buttons.Back == ButtonState.Pressed)
Game.Exit();
Let’s update our yaw rotation code inside of the camera game component so that we can
get the same result with our controller. We can modify our existing code that checks for
left and right to also handle input from our controller. So we modify our two conditional
statements that set the cameraYaw to also check the right thumb stick state of the game
pad we are examining:
if (input.KeyboardState.IsKeyDown(Keys.Left) ||
(input.GamePads[0].ThumbSticks.Right.X < 0))
{
cameraYaw += (spinRate * timeDelta);
}
if (input.KeyboardState.IsKeyDown(Keys.Right) ||
(input.GamePads[0].ThumbSticks.Right.X > 0))
{
cameraYaw -= (spinRate * timeDelta);
}
The thumb stick x and y axis provide a float value between -1 and 1. A value of 0 means
there is no movement. A value of -0.5 means the stick is pushed to the left halfway. A
value of 0.9 would be the stick is pushed to the right 90 percent of the way.
We did not change the keyboard code, we simply added another “or” condition to handle
our controller. We can see it is very simple, as we only needed to check the
ThumbSticks.Left property. We check the x axis of that joystick and if it is less than zero
the user is pushing the stick to the left. We check to see if it is positive (user pushing to
the right) in the second condition. We leave our cameraYaw variable to be set by our spin
rate (taking into account our time delta). At this point, regardless if players are using the
keyboard or the game pad they will get the same result from the game: The camera will
rotate around the y axis. Compile and run the program to try it out. We can also try the
game on the Xbox 360 because we have hooked up our game pad code.
At this point we know how to get access to any of the buttons (they are treated the same
way as the Back button) and either thumb stick but we have not discussed the D-pad yet.
96 CHAPTER 5 Input Devices and Cameras
The D-pad is actually treated like buttons. If we also wanted to allow the player to rotate
the camera left or right by using the D-pad, we simply need to add the following as part
of our condition:
gamePadState.DPad.Left == ButtonState.Pressed
Add that condition along with a check for the right D-Pad being pressed to our code.
Compile and run the code again and make sure that the demo allows us to look left or
right by using the keyboard, thumb stick, and D-pad. The code should now look like the
following:
if (keyboardState.IsKeyDown(Keys.Left) ||
(gamePadState.ThumbSticks.Right.X < 0) ||
(gamePadState.DPad.Left == ButtonState.Pressed))
{
cameraYaw += spinRate;
}
if (keyboardState.IsKeyDown(Keys.Right) ||
(gamePadState.ThumbSticks.Right.X > 0) ||
(gamePadState.DPad.Right == ButtonState.Pressed))
{
cameraYaw -= spinRate;
}
The shoulder buttons are just that—buttons—and we know how to handle those already.
We can determine when we press down on the left or right thumb stick because those are
also considered buttons. However, the final item we discuss regarding our game pad
controller is the triggers. Now, a good use of our triggers for this demo would be to turn
on vibration!
Before we actually determine how to use the triggers, we can look at another property of
the game pad state we have access to and that is if the controller is actually connected or
not. We can check this by getting the value of the IsConnected property.
The trigger values return a float between 0 and 1 to signify how much the trigger is
pressed (0 = not pressed; 1 = fully pressed). The Xbox 360 controller has two motors that
create its vibration. The motor on the left is a low-frequency motor whereas the motor on
the right is a high-frequency motor. We can set the values on both motors in the same
method call. We do this by calling the GamePad.SetVibration method. Because this is just
something we are doing for our demo and not really a part of the library, we will put this
code in our Game1.cs file inside the Update method:
if (input.GamePads[0].IsConnected)
{
GamePad.SetVibration(PlayerIndex.One, input.GamePads[0].Triggers.Left,
input.GamePads[0].Triggers.Right);
}
Working with Input Devices 97
5
The first thing we are doing with this new code is checking to see if the game pad is actually
connected. If it is connected then we set the vibration of both the left and right
motors based on how much the left and right triggers are being pressed. We are calling
the GamePad’s static SetVibration method. There is currently no benefit in wrapping
that into a method inside of our input handler.
We can also change the information being displayed in our window title bar to include
the left and right motor values. This can help you determine what values you should use
as you implement vibration in your games! The following is the code to accomplish that
task:
this.Window.Title = “left: “ +
input.GamePads[0].Triggers.Left.ToString() + “; right: “ +
input.GamePads[0].Triggers.Right.ToString();
Go ahead and add this debug line inside of the IsConnected condition and compile and
run the code to check the progress. We will no longer be able to see our frame rate with
this code so we could just comment out the fps object until we are ready to actually
check on our performance.

Read More......

Working with keyboard Devices

We will be populating the stub we created for handling our input. We are going to create
a stationary camera and a first person. Both of these cameras will need to respond to user
input. We need to learn how to handle input devices and utilize them to move our
camera and fully see the worlds we create.
Keyboard
The first input device we will talk about is the keyboard. XNA provides us with helper
classes that allow us to easily determine the state of our input devices. We determine the
state of our keyboard by declaring a variable to store our keyboard state and then calling
the GetState method on the Keyboard helper object. We can then query that variable to
determine which key (or keys) is being pressed or released. We can start by adding a
private member field to store our keyboard state. We do this via the following code inside
of our InputHandler game component:
private KeyboardState keyboardState;
Then we can find the Update method that was stubbed out for us when the InputHandler
game component was created.
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Escape))
Game.Exit();
We can put this at the very beginning of the Update method. We are simply storing the
state of the keyboard and then checking to see if the Escape key was pressed. If so, we
simply exit the program. It doesn’t get much simpler than that! So now when we run the
program we can exit by pressing the Escape key (instead of having to close the window
with our mouse).
Although being able to exit our game easily is important, we still haven’t done anything
exciting. Let’s set up our camera so we swivel back and forth if the left or right keys are
pressed. To do this we need to add and initialize a new private member field called
cameraReference inside of our Camera game component:
private Vector3 cameraReference = new Vector3(0.0f, 0.0f, -1.0f);
This camera reference direction will not change throughout the game, but we will be
passing it in as a reference so we cannot declare it as a readonly variable. Typically this
value will either be (0,0,1) or (0,0,-1). We chose to have a negative z value so we can
continue to have our camera face the same way.
Now that we have our camera reference direction set up, we need to apply any movement
and rotation to our view of the world. So if the player wants to look left and right we can
adjust our view matrix accordingly so that our view of the world is from a certain angle.
To look left and right we need to rotate around our y axis. We can add the following code
to our Update method right before our call out to the base object’s Update method (we are
still in our Camera class):
Working with Input Devices 91
5
Matrix rotationMatrix;
Matrix.CreateRotationY(MathHelper.ToRadians(cameraYaw), out rotationMatrix);
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference, out cameraTarget);
Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector,
out view);
Because we know we will be rotating, we will create a matrix to hold our rotation. With a
helper function from XNA we will create a matrix with the appropriate values to rotate
our camera on the y axis by a certain number of degrees. We are storing that value in a
variable that we will set with our input devices. We will see how we set that value with
our keyboard soon. Once we have our matrix with all of the translations, scaling, and
rotations that we need (in this case we are only rotating) we can create a transform vector
that will allow us to change the target of the camera. We get this transformed vector by
using another XNA helper method, Vector3.Transform. We then add the transformed
camera reference to our camera position, which will give us our new camera target. To do
this, we could have used the plus (+) operator like the following code:
cameraTarget = cameraPosition + transformedReference;
However, it is much more efficient to use the built-in static Add method of the Vector3
struct because it allows us to pass our vectors by reference instead of having to copy the
values to memory. Finally, we reset our view with our new camera target. We also need to
set the following private member field that we used in the code:
private float cameraYaw = 0.0f;
Now we are to the point where we can compile the code, but our newly added code does
not do anything for us. This is because we are never changing our rotation angle. It stays
at 0 on every frame. Let’s change that now with our keyboard. Inside of our InputHandler
class, we need to update our IInputHandler interface to expose the keyboard state we
retrieved earlier. Let’s add the following code inside of our interface:
KeyboardState KeyboardState { get; }
Now, we need to implement that property inside of the class. An easy way to do this is to
right-click IInputHandler where we derived from it and select Implement Interface. We
will be doing this a couple of times and each time it will create a region so we will have
to clean up the code and remove the extra regions the IDE provides for us. Now we need
to change the get value to retrieve our internal keyboardState value as follows:
92 CHAPTER 5 Input Devices and Cameras
public KeyboardState KeyboardState
{
get { return(keyboardState); }
}
Now that we have exposed our keyboard state we can utilize it inside of our Camera
object. We need to add the following code to our Update method right above the previous
code inside of our camera object:
if (input.KeyboardState.IsKeyDown(Keys.Left))
cameraYaw += spinRate;
if (input.KeyboardState.IsKeyDown(Keys.Right))
cameraYaw -= spinRate;
if (cameraYaw > 360)
cameraYaw -= 360;
else if (cameraYaw < 0)
cameraYaw += 360;
We also need to make sure camera is using the XNA Framework’s Input namespace
because we are accessing the Keys enumeration:
using Microsoft.Xna.Framework.Input;
Finally, we add this constant to the top of our camera class:
private const float spinRate = 2.0f;
In our update code we utilized the current keyboard state we already captured and
checked to see if either the left arrow or right arrow on the keyboard was pressed. If the
player wants to rotate to the left then we add our spin rate constant to our current
camera yaw angle. (Yaw, pitch, and roll are terms borrowed from flight dynamics. Because
we are using a right-handed coordinate system, this means that yaw is rotation around
the y axis, pitch is rotation around the x axis, and roll is rotation around the z axis.) If
the player wants to rotate to the right then we subtract our spin rate constant from our
current camera yaw angle. Finally we just check to make sure that we do not have an
invalid rotation angle.
There is one last thing we need to do before we can run our code again. We need to actually
add our input handler game component to our game’s collection of components. We
can declare our member field as follows:
private InputHandler input;
Now we can actually initialize that variable and add it to the collection inside of our
constructor with this code:
input = new InputHandler(this);
Components.Add(input);
Working with Input Devices 93
5
We can compile and run the code and move knowing that our left and right arrows rotate
the camera. When running we can see that our objects are just flying by. It almost seems
they are blinking we are turning so fast. This is because we are calling our Update statement
as fast as possible. We can modify the game code where we are initializing our fps
variable to use a fixed time step:
fps = new FPS(this, false, true);
For the preceding code to work we need to add another constructor to our FPS code. We
are doing this is so we don’t need to actually pass in our target elapsed time value if we
want it to be the default.
public FPS(Game game, bool synchWithVerticalRetrace, bool isFixedTimeStep)
: this(game, synchWithVerticalRetrace, isFixedTimeStep,
game.TargetElapsedTime) { }
Now when we run the code we can see the objects move by at a consistent and slower
rate. This is because the Update method is now only getting called 60 times a second
instead of whatever rate our machine was running at.
We will notice, however, that as it renders the rectangles that our screen is “choppy.” The
reason is that we are not letting XNA only draw during our monitor’s vertical refresh. We
could do this by setting our second parameter to true and we would see the screen rotate
at a nice even pace with the screen drawing nicely. However, a better way to handle this
is by utilizing the elapsed time between calls to our methods. We need to retrieve the
elapsed time since the last time our Update method was called and then multiply our
spinRate by this delta of the time between calls. We will change the camera code snippet
to match the following:
float timeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (input.KeyboardState.IsKeyDown(Keys.Left))
cameraYaw += (spinRate * timeDelta);
if (input.KeyboardState.IsKeyDown(Keys.Right))
cameraYaw -= (spinRate * timeDelta);
We can modify our game code to call the default constructor again:
fps = new FPS(this);
Now we are just creeping along. This is because our spin rate is so low. We had it low
because we were relying on the update method to be called 60 times per frame, so we
were basically rotating our camera 120 degrees per second. To get the same effect we
simply set our spinRate to 120. The reason is we are now multiplying it by the time
difference between calls. At this point we can safely set our units and know they will be
used on a per-second basis. Now that we have our spinRate utilizing the delta of the time
between calls we are safe to run at any frame rate and have our objects drawn correctly
based on the amount of time that has elapsed.
94 CHAPTER 5 Input Devices and Cameras
We can have it always run at 60 fps in release mode and run as fast as possible in debug
mode by modifying our game code as follows:
#if DEBUG
fps = new FPS(this);
#else
fps = new FPS(this, true, false);
#endif
This allows us to run as fast as we can in debug mode while consistently moving our
objects no matter the frame rate. It allows us to force XNA to only update the screen
during the monitor’s vertical retrace, which would drop us to 60 fps or whatever rate the
monitor is refreshing at.
Making a game update itself consistently regardless of the frame rate can make the game
more complex. We need to calculate the elapsed time (time delta) since the last frame and
use that value in all of our calculations. With the fixed step mode that XNA provides we
could cut down on development time and rely on the fact that the update code will be
called 60 times a second. This is not sufficient if we are writing a library that can be
plugged into games, as those games might not run at a consistent frame rate.

Read More......

Textures

We have a triangle finally drawn on the screen, but it does not look particularly
good. We can fix that by adding a texture. Copy the texture from the
Chapter4\XNADemo\XNADemo folder (texture.jpg) and paste that into our project.
This invokes the XNA Content Pipeline, which we discuss in Part III, “Content Pipeline”.
For now, we just need to know that it makes it available as loadable content complete
with a name by which we can access it. The asset will get the name “texture” (because that
is the name of the file). We need to declare a private member field to store our texture:
68 CHAPTER 4 Creating 3D Objects
private Texture2D texture;
We define our texture as a Texture2D object. This is another class that XNA provides for
us. Texture2D inherits from the Texture class, which allows us to manipulate a texture
resource. Now we need to actually load our texture into that variable. We do this in the
LoadGraphicsContent method. Inside of the loadAllContent condition, add this line of
code:
texture = content.Load(“texture”);
Now we have our texture added to our project and loaded into a variable (with very little
code), but we have yet to associate that texture to the effect that we used to draw the
triangle. We will do that now by adding the following two lines of code right before our
call to effect.Begin inside of our Draw method:
effect.TextureEnabled = true;
effect.Texture = texture;
This simply tells the effect we are using that we want to use textures, and then we actually
assign the texture to our effect. It is really that simple. Go ahead and compile and run
the code to see our nicely textured triangle!

Index Buffers

We have covered a lot of ground so far, but we aren’t done yet. We want to create a
rectangle on the screen and to do this we need another triangle. So that means we need
three more vertices, or do we? Actually, we only need one more vertex to create our
square because the second triangle we need to complete the square shares two of our existing
points already. Feel free to review a couple of sections earlier where we talked about
vertex buffers. We set up three points to make the triangle we just saw. To use the code as
is we would need to create another three points, but two of those points are redundant
and the amount of data it takes to represent the VertexPositionNormalTexture struct is
not minimal, so we do not want to duplicate all of that data if we do not need to.
Fortunately, we do not. XNA provides us with index buffers. Index buffers simply store
indices that correspond to our vertex buffer. So to resolve our current dilemma of not
wanting to duplicate our heavy vertex data we will instead duplicate our index data, which
is much smaller. Our vertex buffer will only store four points (instead of six) and our index
buffer will store six indices that will correspond to our vertices in the order we want them
to be drawn. We need to increase our vertex array to hold four values instead of three.
Make the following change:
vertices = new VertexPositionNormalTexture[4];
An index buffer simply describes the order in which we want the vertices in our vertex
buffer to be drawn in our scene.
Find the InitializeVertices method in our code and add the last point we need for our
rectangle. Try to do this before looking at the following code.
Index Buffers 69
4
//top right
position = new Vector3(1, 1, 0);
textureCoordinates = new Vector2(1, 0);
vertices[3] = new VertexPositionNormalTexture(position, Vector3.Forward,
textureCoordinates);
As you were writing the code, I imagine you were wondering about the texture coordinates
for the points. We finally talked about textures, but not really how we mapped the
texture to the vertices we created. We will take a moment and do that now before we
continue our understanding of index buffers.
Texture coordinates start at the top left at (0,0) and end at the bottom right at (1,1). The
bottom left texture coordinate is (0,1) and the top right is (1,0). Take a look at Figure 4.4
to see an example.

If we wanted to map a vertex to the bottom center pixel of a texture, what should the
values be? The horizontal axis is our x axis and the vertical axis is our y axis. We know we
need a 1 in our y coordinate to get to the very bottom of the texture. To get to the middle
of that bottom row, we would need to take the value in between 0 and 1, which is 0.5. So
if we wanted to map a vertex to the bottom center pixel of a texture, we would map it at
(0.5, 1). Back to our demo: Because the vertex we just added was the top right point of
the rectangle, the texture coordinate we assigned to it was (1,0).
Now that we have a better understanding of why our texture mapped to our triangle
correctly, we can get back to our index buffer. We have added a vertex to our code and
now we need to create an index buffer to reference these four points. We need to create
another private member field called indices:
private short[] indices;
Notice that we declared this as an array of short. We could have used int, but short takes
up less room and we aren’t going to have more than 65,535 indices in this demo. The
next thing we need to do is actually create our method that will initialize our indices.
We will name this InitializeIndices and we will call this method from inside our
LoadGraphicsContent method right after we make the call to InitializeVertices. Make
sure that the vertex was added right before we initialize our vertex buffer and after we
created all of the other vertices. This way the code for InitializeIndices shown next
will work for us. It assumes the latest addition to our list of vertices is at the bottom of
the list.
private void InitializeIndices()
{
//6 vertices make up 2 triangles which make up our rectangle
indices = new short[6];
//triangle 1 (bottom portion)
indices[0] = 0; // top left
indices[1] = 1; // bottom right
indices[2] = 2; // bottom left
//triangle 2 (top portion)
indices[3] = 0; // top left
indices[4] = 3; // top right
indices[5] = 1; // bottom right
}
In this method we know we are going to create two triangles (with three points each) so
we create enough space to hold all six indices. We then populate our indices. We took
care to add our vertices in a clockwise order when adding them to the vertex list, so we
can simply set our first three indices to 0, 1, and 2. The second triangle, however, needs a
little more thought. We know we have to add these in clockwise order, so we can start
with any vertex and work our way around. Let us start with the top left vertex (the first
vertex we added to our list—index of 0). That means we need to set our next index to be
the top right vertex, which is the one we just added to the end of the list. We set that
index to 3. Finally, we set the last point to the bottom right vertex, which was added to
the vertex buffer second and has the index of 1.
Now we have our vertices created, complete with textured coordinates and position and
even normals. We have our indices set up to use the vertex buffer in a way where we did
not have to duplicate any of the complex vertex data. We further saved memory by using
short instead of int because we will only have a few indices we need to store to represent
our 3D object (our rectangle). Also, some older graphic cards do not support 32-bit (int)
index buffers. The only thing left for us to do is to actually modify our code that draws
the primitive to tell it we are now using an index buffer. To do that, find the Draw method
and locate the call to DrawUserPrimitives. We will want to replace that line with the
following line:
graphics.GraphicsDevice.DrawUserIndexedPrimitives(
PrimitiveType.TriangleList, vertices, 0, vertices.Length,
indices, 0, indices.Length / 3);
Index Buffers 71
4
Notice that we changed the method we are calling on the graphics device. We are now
passing in both vertex and index data. Let’s break down the parameters we are passing in.
We still pass in a triangle array as the first parameter and our array of vertices as the
second parameter and we are leaving our vertex offset at 0. The next parameter is new
and simply needs the number of vertices that is in our vertex array. The fifth parameter is
our array of indices (this method has an override that accepts an array of int as well). The
sixth parameter is the offset we want for our index buffer. We want to use all of the
indices so we passed in 0. The final parameter, primitive count, is the same as the final
parameter in the method we just replaced. Because we only have four vertices we needed
to change that to our index array. Our indices array has six references to vertices in it and
we take that value and divide it by three to get the number of triangles that are in our
triangle list. When we compile and run the code we should see a rectangle that was
created with our modified vertex buffer and our new index buffer!
As an exercise, modify the points in our vertex to have the rectangle slanted into the
screen. This will require modifying a couple of our z values from 0 to something else.
Give it a try!

Read More......

Effects

Effects are used to get anything in our XNA 3D game to actually show up on the screen.
They handle things like lights, textures, and even position of the points. We will talk
about effects extensively in Part V, “High Level Shading Language (HLSL).” For now, we
can utilize the BasicEffect class that XNA provides. This keeps us from having to actually
create an effect file so we can get started quickly.
The first thing to notice is that we create a new variable to hold our effect. We do this by
passing in the graphics device as our first parameter and we are passing in null as the
effect pool because we are only using one effect and don’t need a pool to share among
66 CHAPTER 4 Creating 3D Objects
multiple effects. After creating our effect, we want to set some of the properties so we can
use it. Notice we set the world, view, and projection matrices for the effect as well as
telling the effect to turn on the default lighting. We discuss lighting in detail in the HLSL
part of our book, but for now, this will light up the 3D scene so we can see our objects.
TIP
It is a good idea to leave the background color set to Color.CornflowerBlue or some
other nonblack color. The reason for this is if the lights are not set up correctly, the
object will render in black (no light is shining on it). So if the background color is
black, we might think that the object didn’t render at all.
Now back to our code. Notice that we call the Begin method on our effect and we also
call the End method. Anything we draw on the screen in between these two calls will
have that effect applied to them. The next section of code is our foreach loop. This loop
iterates through all of the passes of our effect. Effects will have one or more techniques. A
technique will have one or more passes. For this basic effect, we have only one technique
and one pass. We will learn about techniques and passes in more detail in Part V. At this
point we have another begin and end pair, but this time it is for the pass of the current
(only) technique in our effect. Inside of this pass is where we finally get to draw our triangle
onto the screen. This is done using the DrawUserPrimitives method in the graphics
device object:
graphics.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3);
We are passing in the type of primitive we will be rendering. The primitives we are
drawing are triangles so we are going to pass in a triangle list. This is the most common
primitive type used in modern games. Refer to Table 4.1 for a list of different primitive
types and how they can be used. The second parameter we pass in is the actual vertex
data we created in our InitializeVertices method. The third parameter is the offset of
the point data where we want to start drawing—in our case we want to start with the first
point, so that is 0. Finally, we need to pass in the number of triangles we are drawing on
the screen. We can calculate this by taking the number of points we have stored and
dividing it by 3 (as there are 3 points in a triangle). For our example, this will return one
triangle. If we compile and run the code at this point we should see a triangle drawn on
our screen. It is not very pretty, as it is a dull shade of gray, but it is a triangle nonetheless.
To see a screen shot, refer to Figure 4.3.
Effects 67
4
Member Name Description
LineList Renders the vertices as a list of isolated straight-line segments.
LineStrip Renders the vertices as a single polyline.
PointList Renders the vertices as a collection of isolated points. This value is
unsupported for indexed primitives.
TriangleFan Renders the vertices as a triangle fan.
TriangleList Renders the specified vertices as a sequence of isolated triangles. Each
group of three vertices defines a separate triangle. Back-face culling is
affected by the current winding-order render state.
TriangleStrip Renders the vertices as a triangle strip. The back-face culling flag is
flipped automatically on even-numbered triangles.

Read More......

Creating a Camera

That is enough theory for a bit. We are going to create a camera so we can view our
world. Now we can create a new Windows game project to get started with this section.
We can call this project XNADemo. To begin, we will need to create the following private
member fields:
private Matrix projection;
private Matrix view;
private Matrix world;
We will then need to add a call to InitializeCamera in the beginning of our
LoadGraphicsContent method. The InitializeCamera method will have no return
value. We will begin to populate the method, which can be marked as private, in the next
three points.
Projection
The Matrix struct has a lot of helper functions built in that we can utilize. The
Matrix.CreatePerspectiveFieldOfView is the method we want to look at now.
float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
(float)graphics.GraphicsDevice.Viewport.Height;
Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio,
0.0001f, 1000.0f, out projection);
First we set up a local variable aspectRatio. This is to store, you guessed it, the aspect
ratio of our screen. For the Xbox 360 the aspect ratio of the back buffer will determine
how the game is displayed on the gamer’s TV. If we develop with a widescreen aspect ratio
and the user has a standard TV, the game will have a letterbox look to it. Conversely, if we
develop with a standard aspect ratio and the user has a wide screen, the Xbox 360 will
stretch the display. To avoid this we should account for both situations and then adjust
the value of our aspect ratio variable to the default values of the viewport of the graphics
device like in the preceding code. If we needed to query the default value to which the
gamer had his or her Xbox 360 set, we can gather that information by querying the
DisplayMode property of the graphics device during or after the Initialization method
is called by the framework.
Creating a Camera 61
4
However, if we want to force a widescreen aspect ratio on the Xbox 360 we could set the
PreferredBackBufferWidth and PreferredBackBufferHeight properties on the graphics
object right after creating it. Many gamers do not care for the black bars, so we should use
this with caution. To force a widescreen aspect ratio on Windows is a little more complicated,
but the XNA Game Studio Express documentation has a great “How to” page
explaining how to do it. Once in the documentation, you can find “How to: Restrict
Graphics Devices to Widescreen Aspect Ratios in Full Screen” under the Application
Model in the Programming Guide.
Second, we create our field of view. The first parameter we pass in is 45 degrees. We could
have used MathHelper.ToRadians(45.0f) but there is no need to do the math because the
MathHelper class already has the value as a constant. The second parameter is the aspect
ratio, which we already calculated. The third and fourth parameters are our near and far
clipping planes, respectively. The plane values represent how far the plane is from our
camera. It means anything past the far clipping plane will not be drawn onto the screen.
It also means anything closer to us than the near clipping plane will not be drawn either.
Only the points that fall in between those two planes and are within a 45-degree angle of
where we are looking will be drawn on the screen. The last parameter is where we populate
our projection matrix. This is an overloaded method. (One version actually returns
the projection, but we will utilize the overload that has reference and out parameters, as
they are faster because it doesn’t have to copy the value of the data.)
View
Now that we have our projection matrix set, we can set up our view matrix. To do this we
are going to use another XNA matrix helper method. The Matrix.CreateLookAt method
takes three parameters. Let’s create and initialize these private member fields now.
private Vector3 cameraPosition = new Vector3(0.0f, 0.0f, 3.0f);
private Vector3 cameraTarget = Vector3.Zero;
private Vector3 cameraUpVector = Vector3.Up;
Now we can actually call the CreateLookAt method inside of our InitializeCamera
method. We should add the following code at the end of the method:
Matrix.CreateLookAt(ref cameraPosition, ref cameraTarget,
ref cameraUpVector, out view);
The first parameter we pass in is our camera position. We are passing in the coordinates
(0,0,3) for our camera position to start with, so our camera position will remain at the
origin of the x and y axis, but it will move backward from the origin 3 units. The second
parameter of the CreateLookAt method is the target of where we are aiming the camera.
In this example, we are aiming the camera at the origin of the world Vector3.Zero
(0,0,0). Finally, we pass in the camera’s up vector. For this we use the Up property on
Vector3, which means (0,1,0). Notice we actually created a variable for this so we can pass
it in by reference. This is also an overloaded method, and because we want this to be fast
we will pass the variables in by reference instead of by value. Fortunately, we do not lose
much readability with this performance gain.
62 CHAPTER 4 Creating 3D Objects
World
At this point if we compiled and ran the demo we would still see the lovely blank cornflower
blue screen because we have not set up our world matrix or put anything in the
world to actually look at. Let’s fix that now.
As we saw, the templates provide a lot of methods stubbed out for us. One of these very
important methods is the Draw method. Find this method and add this line of code right
below the TODO: Add your drawing code here comment:
world = Matrix.Identity;
This simply sets our world matrix to an identity matrix, which means that there is no
scaling, no rotating, and no translating (movement). The identity matrix has a translation
of (0,0,0) so this will effectively set our world matrix to the origin of the world.
At this point we have our camera successfully set up but we have not actually drawn
anything. We are going to correct that starting with the next section.
Vertex Buffers


3D objects are made up of triangles. Every object is one triangle or more. For example, a
sphere is just made up of triangles; the more triangles, the more rounded the sphere is.
Take a look at Figure 4.1 to see how this works. Now that we know that every 3D object
we render is made up of triangles and that a triangle is simply three vertices in 3D space,
we can use vertex buffers to store a list of 3D points. As the name implies, a vertex buffer
is simply memory (a buffer) that holds a list of vertices.
Vertex Buffers 63
4
FIGURE 4.1 All 3D objects are made up of triangles.
XNA uses a right-handed coordinate system. This means that the x axis goes from left to
right (left being negative and right being positive), the y axis goes up and down (down
being negative and up being positive), and z goes forward and backward (forward being
negative and backward being positive). We can visualize this by extending our right arm
out to our right and positioning our hand like we are holding a gun. Now rotate our wrist
so our palm is facing the sky. At this point our pointer finger should be pointing to the
right (this is our x axis going in a positive direction to the right). Our thumb should be
pointing behind us (this is our z axis going in a positive direction backward). Now, we
uncurl our three fingers so they are pointing to the sky (this represents the y axis with a
positive direction upward). Take a look at Figure 4.2 to help solidify how the right-handed
coordinate system works.


Now that we know what the positive direction is for each axis we are ready to start plotting
our points. XNA uses counterclockwise culling. Culling is a performance measure
graphic cards take to keep from rendering objects that are not facing the camera. XNA has
three options for culling: CullClockwiseFace, CullCounterClockwiseFace, and None. The
default culling mode for XNA is CullCounterClockwiseFace, so to see our objects we have
to set up our points in the opposite order—clockwise.
TIP
It is helpful to use some graph paper (or regular notebook paper for that matter) to
plot out points. Simply put points where we want them and make sure when we put
them into the code, we do it in a clockwise order.
Let’s plot some points. Ultimately, we want to make a square. We know that all 3D
objects can be made with triangles and we can see that a square is made up of two triangles.
We will position the first triangle at (-1,1,0); (1,-1,0); (-1,-1,0). That means the first
point (-1,1,0) will be positioned on the x axis 1 unit to the left and it will be 1 unit up the
y axis and will stay at the origin on the z axis. The code needed to set up these points is
as follows:
private void InitializeVertices()
{
Vector3 position;
Vector2 textureCoordinates;
vertices = new VertexPositionNormalTexture[3];
//top left
position = new Vector3(-1, 1, 0);
textureCoordinates = new Vector2(0, 0);
vertices[0] = new VertexPositionNormalTexture(position, Vector3.Forward,
textureCoordinates);
//bottom right
position = new Vector3(1, -1, 0);
textureCoordinates = new Vector2(1, 1);
vertices[1] = new VertexPositionNormalTexture(position, Vector3.Forward,
textureCoordinates);
//bottom left
position = new Vector3(-1, -1, 0);
textureCoordinates = new Vector2(0, 1);
vertices[2] = new VertexPositionNormalTexture(position, Vector3.Forward,
textureCoordinates);
}
As we look at this function we can see three variables that have been created: vertex,
position, and textureCoordinates. The vertex variable will store our vertex (point) data.
XNA has different structs that describe the type of data a vertex will hold. In most cases
for 3D games we will need to store the position, normal, and texture coordinates. We
discuss normals later, but for now it is sufficient to know they let the graphics device
know how to reflect light off of the face (triangle). The most important part of the vertex
variable is the position of the point in 3D space. We saw earlier that XNA allows us to
store that information in a Vector3 struct. We can either set the data in the constructor as
we did in this code, or we can explicitly set its X, Y, and Z properties.
We skip over explaining the texture coordinates momentarily, but notice it uses the
Vector2 struct that XNA provides for us.We need to add the following private member
field to our class that we have been using to store our vertices:
private VertexPositionNormalTexture[] vertices;
We need to call this method in our application. The appropriate place to call the
InitializeVertices method is inside of the LoadGraphicsContent method.
Vertex Buffers 65
4
If we compile and run our application now we still do not see anything on the screen.
This is because we have not actually told the program to draw our triangle! We will want
to find our Draw method and before the last call to the base class base.Draw(gameTime),
we need to add the following code:
graphics.GraphicsDevice.VertexDeclaration = new
VertexDeclaration(graphics.GraphicsDevice,
VertexPositionNormalTexture.VertexElements);
BasicEffect effect = new BasicEffect(graphics.GraphicsDevice, null);
world = Matrix.Identity;
effect.World = world;
effect.Projection = projection;
effect.View = view;
effect.EnableDefaultLighting();
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
graphics.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList, vertices, 0,
vertices.Length / 3);
pass.End();
}
effect.End();
You might think there is a lot of code here just to draw the points we have created on the
screen. Well, there is, but it is all very straightforward and we can plow on through.
Before we do, though, let’s take a minute and talk about effects.

Read More......

Transformations Reloaded

An object can have one transformation applied to it or it can have many transformations
applied to it. We might only want to translate (move) an object, so we can update the
object’s world matrix to move it around in the world. We might just want the object to
spin around, so we apply a rotation transformation to the object over and over so it will
rotate. We might need an object we created from a 3D editor to be smaller to fit better in
our world. In that case we can apply a scaling transformation to the object. Of course, we
might need to take this object we loaded in from the 3D editor and scale it down and
rotate it 30 degrees to the left so it will face some object and we need to move it closer to
the object it is facing. In this case we would actually do all three types of transformations
to get the desired results. We might even need to rotate it downward 5 degrees as well,
and that is perfectly acceptable.
We can have many different transformations applied to an object. However, there is a
catch—there is always a catch, right? The catch is that because we are doing these transformations
using matrix math we need to be aware of something very important. We are
multiplying our transformation matrices together to get the results we want. Unlike
multiplying normal integers, multiplying matrices is not commutative. This means that
Matrix A * Matrix B != Matrix B * Matrix A. So in our earlier example where we want to
scale our object and rotate it (two different times) and then move it, we will need to be
careful in which order we perform those operations. We will see how to do this a little
later in the chapter.

Read More......

Creating a Benchmark

To get a baseline for our game loop we will start with a new Windows game project. We
can call this project PerformanceBenchmark. We will add a frame rate counter and
update our window title to show just how many frames per second we are getting “out
of the box.”
Now we can set the following properties inside of the constructor:
//Do not synch our Draw method with the Vertical Retrace of our monitor
graphics.SynchronizeWithVerticalRetrace = false;
//Call our Update method at the default rate of 1/60 of a second.
IsFixedTimeStep = true;
The template creates the GraphicsDeviceManager for us. We set the
SynchronizeWithVerticalRetrace property of the manager to false. The default of this
property is true. As the name suggests, this property synchronizes the call to the Draw
method from inside of the XNA Framework’s game loop to coincide with the monitor’s
refresh rate. If the monitor has a refresh rate of 60 Hz, it refreshes every 1/60 seconds or
60 times every second. By default XNA draws to the screen at the same time the monitor
refreshes to keep the scene from appearing jerky. This is typically what we want. However,
Measure, Measure, Measure 37
3
when measuring the change a piece of code has on our frame rate it is difficult to determine
how we are affecting it if we are always drawing 60 fps. We would not know
anything was wrong until we did something that dropped us below that margin keeping
XNA from calling the Draw method fast enough.
We also set the fixed time step property (IsFixedTimeStep) to true. This is the default
value of this property. This property lets XNA know if it should call the Update method
immediately after drawing to the screen (false) or only after a fixed amount of time has
passed (true). This fixed amount of time is 1/60 second and is stored in the property
TargetElapsedTime, which we can change. At this point we do not need the framework
to call Update as often as possible. For this application it does not really matter because
we are not doing anything inside of our Update method.
Let’s add the following private member fields to our Game1.cs file:
private float fps;
private float updateInterval = 1.0f;
private float timeSinceLastUpdate = 0.0f;
private float framecount = 0;
Finally, let’s add the frame rate calculation inside of our Draw method.
float elapsed = (float)gameTime.ElapsedRealTime.TotalSeconds;
framecount++;
timeSinceLastUpdate += elapsed;
if (timeSinceLastUpdate > updateInterval)
{
fps = framecount / timeSinceLastUpdate; //mean fps over updateIntrval
Window.Title = “FPS: “ + fps.ToString() + “ - RT: “ +
gameTime.ElapsedRealTime.TotalSeconds.ToString() + “ - GT: “ +
gameTime.ElapsedGameTime.TotalSeconds.ToString();
framecount = 0;
timeSinceLastUpdate -= updateInterval;
}
The first thing we are doing with the code is storing the elapsed time since the last time
the Draw method was executed. We then increment our frame count along with the variable
that is keeping a running total of the time. We check to see if enough time has passed,
at which point we update our frame rate. We have the updateInterval set at 1 second, but
we can tweak that number if we would like. Once enough time has passed for us to recalculate
our frame rate, we do just that by taking the number of frames and dividing it by
the time it took us to get inside of this condition. We then update the title of the window
with our fps. We also write out the ElapsedRealTime along with the ElapsedGameTime. To
calculate our fps we used the real time. Play with the first two properties we set to see the
effect it has on the time. Remember the SynchronizeWithVerticalRetrace property determines
how often the Draw method gets called and the IsFixedTimeStep property determines
how often the Update method gets called. We can see that the ElapsedRealTime is
associated to the time it took to call our Draw method while the ElapsedGameTime is associated
with the time it took to call our Update method.
CHAPTER 3 38 Performance Considerations
Finally, we reset our frame count along with the timeSinceLastUpdate variable. Let’s run
the application so we can get our baseline for how our machine is performing.
Now that we have our base number we want to make a note of it. This could be done in
an Excel spreadsheet where we can easily track the changes in our performance. We
should always try to run our performance tests under the same conditions. Ideally,
nothing except the game should be run during all of the benchmark testing.
As an example, let’s add the following code inside of the Draw method:
//bad code that shoud not be replicated
Matrix m = Matrix.Identity;
Vector3 v2;
for (int i = 0; i < 1; i++)
{
m = Matrix.CreateRotationX(MathHelper.PiOver4);
m *= Matrix.CreateTranslation(new Vector3(5.0f));
Vector3 v = m.Translation - Vector3.One;
v2 = v + Vector3.One;
}
It does not do anything other than some 3D math that has absolutely no purpose. The
reason we are going through this exercise is to see how our frame rate will drop as we
increment the upper limit of our for loop. The point is that when we start writing real
functionality inside of the Draw method we can measure how our frame rate is handling
the addition of code. On the included CD, this example is called PerformanceTest1.

Read More......

Creating 3D Objects

In this chapter we examine 3D concepts and how the
XNA Framework exposes different types and objects that
allow us to easily create 3D worlds. We will create a couple
of 3D demos that explain the basics. We will also create 3D
objects directly inside of our code. Finally, we will move
these objects on the screen.
Vertices
Everything in a 3D game is represented by 3D points. There
are a couple of ways to get 3D objects on the screen. We
can plot the points ourselves or we can load them from a
3D file (which has all of the points stored already). Later, in
Chapter 6, “Loading and Texturing 3D Objects,” we will
learn how to load 3D files to use in our games. For now,
we are going to create the points ourselves.
We defined these points with an x, y, and z coordinate (x,
y, z). In XNA we represent a vertex with a vector, which
leads us to the next section.
Vectors
XNA provides three different vector structs for us—
Vector2, Vector3, and Vector4. Vector2 only has an x
and y component. We typically use this 2D vector in 2D
games and when using a texture. Vector3 adds in the z
component. Not only do we store vertices as a vector, but
we also store velocity as a vector. We discuss velocity in
Chapter 19, “Physics Basics.” The last vector struct that
XNA provides for us is a 4D struct appropriately called
Vector4. Later examples in this book will use this struct to
pass color information around as it has four components.
We can perform different math operations on vectors,
which prove to be very helpful. We do not discuss 3D math
in detail in this book as there are many texts out there that
60 CHAPTER 4 Creating 3D Objects
cover it. Fortunately, XNA allows us to use the built-in helper functions without having to
have a deep understanding of the inner workings of the code. With that said, it is
extremely beneficial to understand the math behind the different functions.
Matrices
In XNA a matrix is a 4x 4 table of data. It is a two-dimensional array. An identity matrix,
also referred to as a unit matrix, is similar to the number 1 in that if we multiply any
other number by 1 we always end up with the number we started out with (5 * 1 = 5 ).
Multiplying a matrix by an identity matrix will produce a matrix with the same value as
the original matrix. XNA provides a struct to hold matrix data—not surprisingly, it is
called Matrix.
Transformations
The data a matrix contains are called transformations. There are three common transformations:
translation, scaling, and rotating. These transformations do just that: They transform
our 3D objects.
Translation
Translating an object simply means we are moving an object. We translate an object from
one point to another point by moving each point inside of the object correctly.
Scaling
Scaling an object will make the object larger or smaller. This is done by actually moving
the points in the object closer together or further apart depending on if we are scaling
down or scaling up.
Rotation
Rotating an object will turn the object on one or more axes. By moving the points in 3D
space we can make our object spin.


Transformations Reloaded

tag: transformation,reloaded,xna

An object can have one transformation applied to it or it can have many transformations
applied to it. We might only want to translate (move) an object, so we can update the
object’s world matrix to move it around in the world. We might just want the object to
spin around, so we apply a rotation transformation to the object over and over so it will
rotate. We might need an object we created from a 3D editor to be smaller to fit better in
our world. In that case we can apply a scaling transformation to the object. Of course, we
might need to take this object we loaded in from the 3D editor and scale it down and
rotate it 30 degrees to the left so it will face some object and we need to move it closer to
the object it is facing. In this case we would actually do all three types of transformations
to get the desired results. We might even need to rotate it downward 5 degrees as well,
and that is perfectly acceptable.
We can have many different transformations applied to an object. However, there is a
catch—there is always a catch, right? The catch is that because we are doing these transformations
using matrix math we need to be aware of something very important. We are
multiplying our transformation matrices together to get the results we want. Unlike
multiplying normal integers, multiplying matrices is not commutative. This means that
Matrix A * Matrix B != Matrix B * Matrix A. So in our earlier example where we want to
scale our object and rotate it (two different times) and then move it, we will need to be
careful in which order we perform those operations. We will see how to do this a little
later in the chapter.

Read More......

Creating a Micro-Benchmark Framework

When we are trying to make a particular piece of code run faster because we see that it is
taking more time compared to everything else in our application, we will need to
compare different implementations of completing the same task. This is where microbenchmark
testing can help.
Micro-benchmark testing allows us to take a close look at how fast small bits of code are
performing. There are a couple of items to keep in mind as we use micro-benchmark
testing, though. The first is that we cannot exactly determine best practices from a microbenchmark
test because it is such an isolated case. The second is that although a piece of
code might perform faster in a micro-benchmark test, it might very well take up a lot
more memory and therefore cause the garbage collector to collect its garbage more often.
Optimization Suggestions 43
3
The point here is that although micro-benchmark testing is good and we should do it
(which is why we are going to build a framework for it) we need to be careful of any
assumptions we make solely on what we find out from our micro-benchmark tests.
XNA Game Studio Express not only lets us create game projects, but also allows us to
create library projects. When the library projects are compiled they can be used by other
applications—a game, a Windows form, or even a console application.
We are going to create another application, but this time it is going to be a normal
Windows Game Library project. This class should be called CheckPerformance. We will be
utilizing this library from a console application. The code for the CheckPerformance can
be found in Listing 3.1. The purpose of this class is to create methods that perform the
same tasks different ways. We will then create a console application that calls the different
methods and measure the amount of time it takes to process each method.
LISTING 3.1 The CheckPerformance class has methods that produce the same results
through different means.
public class CheckPerformance
{
private Vector3 cameraReference = new Vector3(0, 0, -1.0f);
private Vector3 cameraPosition = new Vector3(0, 0, 3.0f);
private Vector3 cameraTarget = Vector3.Zero;
private Vector3 vectorUp = Vector3.Up;
private Matrix projection;
private Matrix view;
private float cameraYaw = 0.0f;
public CheckPerformance() { }
public void TransformVectorByValue()
{
Matrix rotationMatrix = Matrix.CreateRotationY(
MathHelper.ToRadians(45.0f));
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference = Vector3.Transform(cameraReference,
rotationMatrix);
// Calculate the position the camera is looking at.
cameraTarget = cameraPosition + transformedReference;
}
public void TransformVectorByReference()
{
Matrix rotationMatrix = Matrix.CreateRotationY(
MathHelper.ToRadians(45.0f));
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
CHAPTER 3 44 Performance Considerations
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference,
out cameraTarget);
}
public void TransformVectorByReferenceAndOut()
{
Matrix rotationMatrix = Matrix.CreateRotationY(
MathHelper.ToRadians(45.0f));
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference,
out cameraTarget);
}
public void TransformVectorByReferenceAndOutVectorAdd()
{
Matrix rotationMatrix;
Matrix.CreateRotationY(MathHelper.ToRadians(45.0f),
out rotationMatrix);
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
Vector3.Add(ref cameraPosition, ref transformedReference,
out cameraTarget);
}
public void InitializeTransformWithCalculation()
{
float aspectRatio = (float)640 / (float)480;
projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f), aspectRatio, 0.0001f, 1000.0f);
view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
}
public void InitializeTransformWithConstant()
{
Optimization Suggestions 45
3
LISTING 3.1 Continued
float aspectRatio = (float)640 / (float)480;
projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver4, aspectRatio, 0.0001f, 1000.0f);
view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
}
public void InitializeTransformWithDivision()
{
float aspectRatio = (float)640 / (float)480;
projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.Pi / 4, aspectRatio, 0.0001f, 1000.0f);
view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
}
public void InitializeTransformWithConstantReferenceOut()
{
float aspectRatio = (float)640 / (float)480;
Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f), aspectRatio, 0.0001f, 1000.0f,
out projection);
Matrix.CreateLookAt(
ref cameraPosition, ref cameraTarget, ref vectorUp, out view);
}
public void InitializeTransformWithPreDeterminedAspectRatio()
{
Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f), 1.33333f, 0.0001f, 1000.0f,
out projection);
Matrix.CreateLookAt(
ref cameraPosition, ref cameraTarget, ref vectorUp, out view);
}
public void CreateCameraReferenceWithProperty()
{
Vector3 cameraReference = Vector3.Forward;
Matrix rotationMatrix;
Matrix.CreateRotationY(
MathHelper.ToRadians(45.0f), out rotationMatrix);
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
CHAPTER 3 46 Performance Considerations
LISTING 3.1 Continued
cameraTarget = cameraPosition + transformedReference;
}
public void CreateCameraReferenceWithValue()
{
Vector3 cameraReference = new Vector3(0, 0, -1.0f);
Matrix rotationMatrix;
Matrix.CreateRotationY(
MathHelper.ToRadians(45.0f), out rotationMatrix);
// Create a vector pointing the direction the camera is facing.
Vector3 transformedReference;
Vector3.Transform(ref cameraReference, ref rotationMatrix,
out transformedReference);
// Calculate the position the camera is looking at.
cameraTarget = cameraPosition + transformedReference;
}
public void RotateWithoutMod()
{
cameraYaw += 2.0f;
if (cameraYaw > 360)
cameraYaw -= 360;
if (cameraYaw < 0)
cameraYaw += 360;
float tmp = cameraYaw;
}
public void RotateWithMod()
{
cameraYaw += 2.0f;
cameraYaw %= 30;
float tmp = cameraYaw;
}
public void RotateElseIf()
{
cameraYaw += 2.0f;
if (cameraYaw > 360)
cameraYaw -= 360;
Optimization Suggestions 47
3
LISTING 3.1 Continued
else if (cameraYaw < 0)
cameraYaw += 360;
float tmp = cameraYaw;
}
}
We do not need to be concerned with the actual contents of the different methods. The
main concept we need to understand at this point is we have different groups of methods
that do the same task but are executed in different ways. We discuss the details of the
Matrix in Chapter 4, “Creating 3D Objects.” For now we can take a look at the last three
methods in the listing and see they are all doing the same thing. All three methods are
adding 2 to a variable cameraYaw and then making sure that the value is between 0 and
360. The idea is that this code would be inside of the game loop reading input from a
device and updating the cameraYaw variable appropriately.
Now we can create the console application that will actually call that class. We need to
add a new Console Application project to the solution and can call this project
XNAPerfStarter. We can name this project XNAPerformanceChecker. The code for
Program.cs is given in Listing 3.2.
LISTING 3.2 The program measures the amount of time it takes to execute the different
CheckPerformance methods.
class Program
{
static int timesToLoop = 10000;
static void Main(string[] args)
{
while (true)
{
XNAPerformanceChecker.CheckPerformance cp =
new XNAPerformanceChecker.CheckPerformance();
Stopwatch sw = new Stopwatch();
//Call all methods once for any JIT-ing that needs to be done
sw.Start();
cp.InitializeTransformWithCalculation();
cp.InitializeTransformWithConstant();
cp.InitializeTransformWithDivision();
cp.InitializeTransformWithConstantReferenceOut();
cp.TransformVectorByReference();
cp.TransformVectorByValue();
CHAPTER 3 48 Performance Considerations
LISTING 3.1 Continued
cp.TransformVectorByReferenceAndOut();
cp.TransformVectorByReferenceAndOutVectorAdd();
cp.CreateCameraReferenceWithProperty();
cp.CreateCameraReferenceWithValue();
sw.Stop();
sw.Reset();
int i;
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.InitializeTransformWithCalculation();
sw.Stop();
PrintPerformance(“ Calculation”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.InitializeTransformWithConstant();
sw.Stop();
PrintPerformance(“ Constant”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.InitializeTransformWithDivision();
sw.Stop();
PrintPerformance(“ Division”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.InitializeTransformWithConstantReferenceOut();
sw.Stop();
PrintPerformance(“ConstantReferenceOut”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.InitializeTransformWithPreDeterminedAspectRatio();
sw.Stop();
Optimization Suggestions 49
3
LISTING 3.2 Continued
PrintPerformance(“ AspectRatio”, ref sw);
sw.Reset();
Console.WriteLine();
Console.WriteLine(“——————————————————————-”);
Console.WriteLine();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.TransformVectorByReference();
sw.Stop();
PrintPerformance(“ Reference”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.TransformVectorByValue();
sw.Stop();
PrintPerformance(“ Value”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.TransformVectorByReferenceAndOut();
sw.Stop();
PrintPerformance(“ReferenceAndOut”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.TransformVectorByReferenceAndOutVectorAdd();
sw.Stop();
PrintPerformance(“RefOutVectorAdd”, ref sw);
sw.Reset();
Console.WriteLine();
Console.WriteLine(“——————————————————————-”);
Console.WriteLine();
sw.Start();
CHAPTER 3 50 Performance Considerations
LISTING 3.2 Continued
for (i = 0; i < timesToLoop; i++)
cp.CreateCameraReferenceWithProperty();
sw.Stop();
PrintPerformance(“Property”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.CreateCameraReferenceWithValue();
sw.Stop();
PrintPerformance(“ Value”, ref sw);
sw.Reset();
Console.WriteLine();
Console.WriteLine(“——————————————————————-”);
Console.WriteLine();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.RotateWithMod();
sw.Stop();
PrintPerformance(“ RotateWithMod”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.RotateWithoutMod();
sw.Stop();
PrintPerformance(“RotateWithoutMod”, ref sw);
sw.Reset();
sw.Start();
for (i = 0; i < timesToLoop; i++)
cp.RotateElseIf();
sw.Stop();
PrintPerformance(“ RotateElseIf”, ref sw);
sw.Reset();
string command = Console.ReadLine();
Optimization Suggestions 51
3
LISTING 3.2 Continued
if (command.ToUpper().StartsWith(“E”) ||
command.ToUpper().StartsWith(“Q”))
break;
}
}
static void PrintPerformance(string label, ref Stopwatch sw)
{
Console.WriteLine(label + “ – Avg: “ +
((float)((float)(sw.Elapsed.Ticks * 100) /
(float)timesToLoop)).ToString(“F”) +
“ Total: “ + sw.Elapsed.TotalMilliseconds.ToString());
}
}
We need to also add the following using clause to the top of our Program.cs file:
using System.Diagnostics;
The System.Diagnostics class gives us access to the Stopwatch we are using to keep track
of the time it takes to process the different methods. After starting the timer we then loop
100,000 times and call a method in the CheckPerformance class we created earlier. Once
the loop finishes executing the method the specified number of times, we stop the stopwatch
and print out our results to the console. When using the Stopwatch object we need
to make sure that if we want to start another test that we first call the Reset method. This
isn’t built into the Stop method in case we just want to pause the timer and start it back
up for some reason. We could also use the static StartNew method instead of the instance
Start method. The StartNew method effectively resets the timer as it returns a new
instance of the Stopwatch.
When we are trying to measure performance on pieces of code that perform very fast
(even inside of a large loop) it is important to be able to track exactly how much time it
took, even down to the nanosecond level.
Typically timing things in seconds does not give us the granularity we need to see how
long something is really taking, so the next unit of time we can measure against is
milliseconds. There are 1,000 milliseconds in a second. Next comes the microsecond, and
there are 1,000 microseconds in a millisecond. Next is the tick, which is what the
TimeSpan object uses. There are 10 ticks in a microsecond. Finally, we come to the
nanosecond. There are 100 nanoseconds in each tick. A nanosecond is 1/1,000,000,000
(one billionth) of a second. Table 3.1 shows the relationships between the different
measurements of time.
CHAPTER 3 52 Performance Considerations
LISTING 3.2 Continued
TABLE 3.1 Time Measurement Relationships
Nanoseconds Ticks Microseconds Milliseconds Seconds
100 1 0.1 0.0001 0.0000001
10,000 100 10.0 0.0100 0.0000100
100,000 1,000 100.0 0.1000 0.0001000
1,000,000 10,000 1,000.0 1.0000 0.0010000
10,000,000 100,000 10,000.0 10.0000 0.0100000
100,000,000 1,000,000 100,000.0 100.0000 0.1000000
1,000,000,000 10,000,000 1,000,000.0 1,000.0000 1.0000000
PrintPerformance, our method to print out the performance measurements, takes in the
label that describes what we are measuring along with a reference to Stopwatch object.
TimeSpan is the type the .NET Framework uses to measure time. The smallest unit of time
measurement this type allows is a tick.
Because we want to measure our time in nanoseconds, we multiply the number of elapsed
ticks by 100. Then we take the total number of nanoseconds and divide by the number of
times we executed the method. Finally, we display the average number of nanoseconds
along with total number of milliseconds the task took to execute.
When we print out our measurements we want the average time it took to execute a
method for the number of iterations we told it to loop. The reason we do this instead of
just running it once is so that we can easily determine a more accurate number. In fact,
we even run an outer loop (that we exit out of by entering text that starts with “E” or
“Q”) to account for anomalies in performance on the machine in general.
An additional item to note about this code is that we call each method of the
CheckPerformance object once before we start measuring execution times. The reason we
do this is so the compiler can do any just-in-time compiling for the methods we will be
calling so we are not taking that time into account.

Read More......

Understanding the Garbage Collector

A big plus of writing managed code is the fact that we do not need to worry about
memory leaks from the sense of losing pointers to referenced memory. We still have
“memory leaks” in managed code, but whenever the term is used it is referring to not
decommissioning variables in a timely fashion. We would have a memory leak if we kept
a handle on a pointer that we should have set to null. It would remain in memory until
the game exits.
We should use the using statement. An example of the using statement can be found in
the program.cs file that is generated for us by the game template. The entry point of the
program uses this using statement to create our game object and then to call its Run
method. The using statement effectively puts a try/finally block around the code while
putting a call to the object’s Dispose method inside of the finally block.
Garbage collection concerns on Windows are not as large as those on the Xbox 360.
However, if we optimize our code to run well on the Xbox 360 in regard to garbage
collection, the game will also perform well on Windows.

Read More......

Managing Memory

There are two types of objects in the .NET Framework: reference and value. Examples of
value types are enums, integral types (byte, short, int, long), floating types (single, double,
float), primitive types (bool, char), and structs. Examples of objects that are reference
types are arrays, exceptions, attributes, delegates, and classes. Value types have their data
stored on the current thread’s stack and the managed heap is where reference types find
themselves.
By default, when we pass variables into methods we pass them by value. This means for
value types we are actually passing a copy of the data on the stack, so anything we do to
that variable inside of the method does not affect the original memory. When we pass in
a reference type we are actually passing a copy of the reference to the data. The actual
data is not copied, just the address of the memory. Because of this, we should pass large
CHAPTER 3 40 Performance Considerations
value types by reference instead of by value when appropriate. It is much faster to copy
an address of a large value type than its actual data.
We use the ref keyword to pass the objects as reference to our methods. We should not
use this keyword on reference types as it will actually slow things down. We should use
the keyword on value types (like structs) that have a large amount of data it would need
to copy if passed by value.
The other thing to note is that even if we have a reference type and we pass it into a
method that takes an object type and we box (implicitly or explicitly), then a copy of the
data is actually created as well—not just the address to the original memory. For example,
consider a class that takes a general object type (like an ArrayList’s Add method). We pass
in a reference type, but instead of just the reference being passed across, a copy of the
data is created and then a reference to that copy of the data is passed across. This eats up
memory and causes the garbage collector to run more often. To avoid this we need to use
generics whenever possible.

Read More......

Installing Visual C# Express

To get started, we must have the software installed. Let’s start by installing Visual C#
Express. Visual C# Express is the IDE that is required to run XNA Game Studio Express.
XNA requires C# due to how the Content Pipeline is used. There are some people who
have successfully created demos using other languages such as VB.NET and even F#.
However, this is not supported by Microsoft currently and won’t be discussed in this
book. This book assumes you have a good understanding of C#. If you know C++, Java, or
VB.NET, you should be able to pick up C# pretty quickly.
I am going to be detailed in the steps to make sure that anyone who has not worked with
Visual C# Express will be able to get it installed with no issues. Feel free to skip this
section if you already have Visual C# Express installed.
To install Visual C# Express, follow these steps:
1. You will need to be connected to the Internet to install the application. The application
can be downloaded by browsing to
http://msdn.microsoft.com/vstudio/express/downloads/ and clicking the Visual C#
Express Go button to download the vcssetup.exe setup program.
2. Optional. On the Welcome to Setup screen select the check box to send data about
your setup experience to Microsoft. This way if something goes awry, Microsoft can
get the data and try to make the experience better the next time around. This
screen is shown in Figure 1.1.
11
1
Installing Visual C# Express
FIGURE 1.1 Select the check box if you want the system to provide feedback to Microsoft
about your installation experience.
3. Click Next to continue.
4. The next screen is the End-User License Agreement. If you accept the terms, select
the check box and click Next.
5. The following screen, shown in Figure 1.2, has two installation options you can
check. Neither of these options is required to utilize XNA.
FIGURE 1.2 Neither of these options is required to utilize XNA.
CHAPTER 1 Introducing the XNA Framewor12 k
6. Click Next to continue.
7. The next screen, shown in Figure 1.3, asks where we would like to install Visual C#
Express. It is going to install other required applications including Microsoft .NET
Framework 2.0. This is required, as C# runs on the .NET Framework. You will also
notice it requires more than 300MB of space.
8. Click Next to continue.
FIGURE 1.3 Specify which directory you want Visual C# Express to be installed in.
9. Now we are looking at the Installation Progress screen where we will be able to
monitor the progress of the installation.
10. Finally, on the Setup Complete screen we can see the Windows Update link we can
click on to get any of the latest service packs for Visual C# Express.
11. Click Exit to complete the installation.
We have successfully installed the first piece of the pie to start creating excellent games
with XNA! Before we continue to the next piece of software, we need to open up Visual
C# Express. It might take a couple of minutes to launch the first time the application is
loaded. Once the Visual C# Express is loaded we should see the Start Page as shown in
Figure 1.4.
Installing Visual C# Express 13
1
FIGURE 1.4 This is the Start Page inside of Visual C# Express.
The following procedure is optional, but it does ensure that everything is working
correctly on our machine.
1. In the Recent Projects section, find Create Project and click the link. You can also
create a new project under the File menu.
2. Visual C# Express installed several default templates that we can choose from. Select
the Windows Application template as displayed in Figure 1.5.
3. You can leave the name set to WindowsApplication1 as we will just be discarding
this project when we are done.
FIGURE 1.5 The New Project dialog box allows you to choose from the default templates to
create an application.
CHAPTER 1 Introducing the XNA Framewor14 k
4. Click OK to create the application.
At this point a new project should have been created and we should be looking at a blank
Windows Form called Form1.
5. Press Ctrl+F5 or click Start Without Debugging on the Debug menu.
If everything compiled correctly, the form we just saw in design mode should actually
be running. Granted, it doesn’t do anything, but it does prove that we can compile and
run C# through Visual C# Express. The end result can be seen in Figure 1.6. Let’s close
down the application we just created as well as Visual C# Express. Feel free to discard
the application.
FIGURE 1.6 This is a C# Windows Form application after compiling and running the default
template.
Installing the DirectX Runtime
We also need the DirectX 9 runtime if it isn’t already on the machine. To get started,
follow these steps:
1. Run the dxwebsetup.exe file from Microsoft’s website. This can be found by clicking
on the DirectX Runtime Web Installer link at the bottom of the Creator’s Club
Resources—Essentials web page http://creators.xna.com/Resources/Essentials.aspx.
This file contains the redistribution package of the February 2007 DirectX 9.
You will need to be connected to the Internet so it can completely install the
application.
2. We are greeted with the End-User License Agreement. Handle with care.
3. The next screen is a dialog box asking where we would like the installation files to
be stored. We can pick any directory we want as long as we remember it so we can
actually install the runtime—we are simply extracting the files needed to install the
runtime.
4. Click OK to continue.
5. We will be prompted to create that directory if the directory entered doesn’t exist.
Click Yes to continue.
6. Wait for the dialog box with the progress bar to finish unpacking the files.
Now we can actually install the runtime by following these steps:
1. Browse to the folder where we installed the files and run the dxsetup.exe file to
actually install DirectX 9 onto the machine.
2. The welcome screen we see includes the End-User License Agreement. Select the
appropriate radio button to continue.
3. Following the agreement is a screen stating that it will install DirectX—click Next.
4. Once it finishes installing (a progress bar will be visible while it is installing the
files) we will be presented with the Installation Complete screen.
5. Simply click Finish to exit the setup.
Now, we can move on to installing XNA Game Studio Express.
Installing XNA Game Studio Express
To use XNA Game Studio Express we must use Visual C# Express. We cannot use Visual
Studio .NET Professional nor can we use any other IDE. Although there are people who
have successfully been able to run XNA and even get the Content Pipeline (which we talk
about in Part III of the book) to work in Visual Studio .NET Professional, it is not officially
supported by Microsoft and is not covered in this book.
WARNING
You must run the Visual C# Express IDE at least one time before installing XNA Game
Studio Express. If this is not done, not all of the functionality will be installed. If XNA
Game Studio Express was installed prematurely, you will need to uninstall XNA Game
Studio Express and run Visual C# Express and then exit the IDE. Then you will be able
to reinstall XNA Game Studio Express.
To get started complete the following steps:
1. Run the xnagse_setup.msi file from Microsoft’s website. The file can be downloaded
by clicking on the top link of the Creator’s Club Resources—Essentials web site
http://creators.xna.com/Resources/Essentials.aspx.
2. Click Next to get past the setup welcome screen.
3. The next screen is the End-User License Agreement. If you accept the terms, select
the check box and click Next.
4. This will open up a notification dialog box that explains that the Windows Firewall
will have a rule added to it to allow communication between the computer and the
Xbox 360. This can be seen in Figure 1.7.
Installing XNA Game Studio Express 15
1
FIGURE 1.7 XNA Game Studio Express modifies the Windows Firewall so an Xbox 360 and
the PC can talk to each other.
5. Click Install to continue. The next screen shows the progress of the installation.
6. Once it has completed installing all of the required files we will be presented with
the completion dialog box. Simply click Finish to exit the setup.
After we have installed XNA Game Studio Express, we can go to the Start menu and see it
added a few more items than those contained in the IDE. Make sure to take time and read
through some of the XNA Game Studio Express documentation. There is also a Tools
folder that contains a couple of tools we will be looking at later. We will be discussing the
XACT tool in Chapter 6, “Loading and Texturing 3D Objects,” and the XNA Framework
Remote Performance Monitor for Xbox 360 application in Chapter 3, “Performance
Considerations.” Go ahead and open the IDE by clicking XNA Game Studio Express on
the Start menu.
Hmm, this looks identical to the Visual C# Express IDE. There is a good reason for this—it
is the same application! When we installed XNA Game Studio Express it added properties
to Visual C# Express to allow it to behave differently under certain circumstances. Mainly
it added some templates, which we will look at shortly, and it added the ability for Visual
C# Express to handle content via the XNA Content Pipeline. It also added a way for us to
send data to our Xbox 360, as we will see in the next chapter.

Read More......

Introducing the XNA Framework and XNA Game Studio Express

Most developers I know decided to enter the computer
field and specifically programming because of computer
games. Game development can be one of the most challenging
disciplines of software engineering—it can also be
the most rewarding!
Never before has it been possible for the masses to create
games for a game console, much less a next generation
game console. We are coming in on the ground floor of a
technology that is going to experience tremendous growth.
Microsoft is leading the way into how content will be
created for game consoles. Soon other game console manufacturers
will be jumping at a way to allow the public to
create content for their machines. The great news for the
Xbox 360 is that Microsoft has spent so much time over
the years creating productive and stable development environments
for programmers. We will be installing one of
Microsoft’s latest integrated development environments
(IDEs) in this chapter. Before we get to that, let’s take a look
at the technology we discuss in this site—XNA.

What Is the XNA Framework?
You have probably heard the statement, “To know where
you are going, you need to know where you have been.”
I am uncertain if that is entirely true, but I do believe it
applies here. Before we dig into exactly what XNA is and
what it can do for us, let’s take a moment to look at
DirectX because that is what the XNA Framework is
built on.

The Foundation of the XNA Framework
Let’s take a journey back to the days of DOS on the PC. When programming games,
graphic demos, and the like in DOS, programmers typically had to write low-level code to
talk directly to the sound card, graphics cards, and input devices. This was tedious and
the resulting code was error prone because different manufacturers would handle different
BIOS interrupts, IO ports, and memory banks—well, differently, so the code would work
on one system and not another.
Later, Microsoft released the Windows 95 operating system. Many game programmers
were skeptical at writing games for Windows—and rightly so—because there was no way
to get down to hardware level to do things that required a lot of speed. Windows 95 had
a protected memory model that kept developers from directly accessing the low-level
interrupts of the hardware.
To solve this problem, Microsoft created a technology called DirectX. It was actually
called Windows Game SDK to begin with, but quickly switched names after a reporter
poked fun at the API names DirectDraw, DirectSound, and DirectPlay, calling the SDK
Direct “X.” Microsoft ran with the name and DirectX 1.0 was born a few months after
Windows 95 was released. I remember working with DirectDraw for a couple of demos
back when this technology first came out.
Because of DirectX, developers had a way to write games with one source that would work
on all PCs regardless of their hardware. Hardware vendors were eager to work with
Microsoft on standardizing an interface to access their hardware. They created device
drivers to which DirectX would map its API, so all of the work that previously had to be
done by game programmers was taken care of, and programmers could then spend their
time doing what they wanted to—write games! Vendors called this a Hardware
Abstraction Layer (HAL). They also developed a Hardware Emulation Layer (HEL), which
emulates hardware through software in case hardware isn’t present. Of course, this is
slower but it allowed certain games to be run on machines with no special hardware.
After a couple of years Microsoft released DirectX 3.0, which ran on Windows NT 4 as
well as Windows 95. As part of those upgrades, they introduced Direct3D. This allowed
developers to create 3D objects inside of 3D worlds. DirectX 4 was never released, but
DirectX 5 was released in 1997 and later had some upgrades to work under Windows 98.
When DirectX 8 came on the scene in 2000, some of the newly available graphics hardware
had vertex and pixel shaders. As a result, Microsoft added in a way to pass custom
program code to the hardware. Through assembly code, the game developer could manipulate
the data the main game passed to the graphics card. This assembly code was
consumed directly by the graphics hardware.
When there was no graphics hardware, games were slow, but they were very flexible.
Later, as hardware rendering became prominent, the games were faster, but they were not
very flexible in that all of the games really started to look the same. Now with shaders,
the speed of the hardware is combined with the flexibility for each game to render and
light its 3D content differently.

This brings us to present-day DirectX: We are up to DirectX 9 and 10. Before I talk about
DirectX 9, I spend some time talking about DirectX 10. DirectX 10 was released at the
same time as Microsoft Windows Vista. In fact, DirectX 10 only works on Vista. This is
largely due to the fact that Microsoft has made major changes in the driver model for this
operating system. DirectX 10 also requires Shader Model 4.0 hardware.
The Xbox 360 runs on DirectX 9 plus some additional partial support for Shader Model
3.0 functionality. DirectX 9 is the foundation for Managed DirectX, an API that exposed
the core DirectX functionality to .NET Framework developers. There was a lot of concern
about whether this “wrapper” could be as fast as the C++ counterparts. Fortunately, it was
almost as fast—about 98 percent was the benchmark touted. I experienced these benchmark
speeds firsthand while on the beta team for this technology. I fell in love with
Managed DirectX.
The XNA Framework used the lessons learned from Managed DirectX and used that foundation
as a launching pad. To be clear, XNA was built from the ground up and was not
built on top of Managed DirectX. It didn’t use the same namespaces as Managed DirectX
and is not simply pointing to the Managed DirectX methods in the background.
Although XNA utilizes DirectX 9 in the background, there are no references to DirectX’s
API like there were in Managed DirectX.
XNA Today
XNA is actually a generic term much like the term .NET. XNA really refers to anything
that Microsoft produces that relates to game developers. The XNA Framework is the API
we are discussing. The final piece to XNA is the XNA Game Studio Express application,
which we discuss in detail later. This is the IDE we use to develop our XNA games.
TIP
In this book, whenever we use the term XNA, we are really referring to the XNA
Framework unless otherwise noted.
XNA allows us to do a lot of things. We have easy access to the input devices (keyboard,
game pad or controller, mouse). XNA gives us easy access to the graphics hardware. We
are able to easily control audio through XNA. XNA provides the ability for us to store
information like high scores and even saved games. XNA does not currently have any
networking capability. Microsoft wants to use the Xbox Live technology for adding
network support to XNA. However, there is more work to be done to make sure Microsoft
can provide multiplayer functionality in a secure manner.
To get started using XNA we have to install some software. We need to install the latest
version of DirectX 9 as well as have a graphics card that supports DirectX 9.0c and Shader
Model 1.1. (You should get a card that supports Shader Model 2.0 as some of the examples,
including the starter kit we use in this chapter and the next one, will not run
without it.) We also need to install Visual C# Express, the DirectX 9 runtime, and finally
XNA Game Studio Express. Fortunately, all of the software is free! If you don’t have
10 CHAPTER 1 Introducing the XNA Framework and XNA Game Studio Express
graphics hardware that can support Shader Model 2.0 you can pick up a card relatively
inexpensively for about $35 USD. If possible, you should purchase a graphics card that
can support Shader Model 3.0, as a couple of examples at the end of the book require it.
At this point, games cannot be created for commercial use on the Xbox 360 but Microsoft
has mentioned they are interested in supporting commercial games in future versions.
Fortunately, we can create community games for the Xbox 360 with the Express versions.
XNA Game Studio Express is great for the game hobbyist, a student, or someone just
getting started because you do not have to shell out a lot of (any!) money to get up and
running. One exception to this is if you actually want to deploy your games on your
Xbox 360. To do that, you will need to subscribe to the XNA Creators Club for $99 USD a
year (or $49 USD for four months). Remember, writing games for the PC using XNA is
totally free!
Oh, in case you are wondering what XNA stands for, XNA’s Not Acronymed (or so
Microsoft says in the XNA FAQ).

Read More......