Note: This section is not necessary if you started with tutorial #1 after 12/10/2008
In this mini-tutorial, we will be making some minor updates to the engine. First, we will be changing the utility classes to static classes. Remove the instances of MathUtil and GraphicsUtil from the Engine class. Then, add the modifier ‘static’ before the class definition and methods for the two classes.
public static class GraphicsUtil
{
// Creates a RenderTarget2D with the specified parameters
public static RenderTarget2D CreateRenderTarget()
{
return CreateRenderTarget(Engine.GraphicsDevice.Viewport.Width,
Engine.GraphicsDevice.Viewport.Height);
}
// Creates a RenderTarget2D with the specified parameters
public static RenderTarget2D CreateRenderTarget(int Width, int Height)
{
return CreateRenderTarget(Width, Height,
Engine.GraphicsDevice.DisplayMode.Format);
}
etc, etc...
Second, the Rectangle property in I2DComponent should be a Rectangle.
public interface I2DComponent
{
Rectangle Rectangle { get; set; }
}
Now we will add a few more methods to the MathUtil class:
// Converts a rotation vector into a rotation matrix
public static Matrix Vector3ToMatrix(Vector3 Rotation)
{
return Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);
}
// Converts a rotation matrix into a rotation vector
public static Vector3 MatrixToVector3(Matrix Rotation)
{
Quaternion q = Quaternion.CreateFromRotationMatrix(Rotation);
return new Vector3(q.X, q.Y, q.Z);
}
Now change these methods in the MathUtil to use matrices for rotation:
// Creates a world matrix
public static Matrix CreateWorldMatrix(Vector3 Translation)
{
return CreateWorldMatrix(Translation, Matrix.Identity);
}
// Creates a world matrix
public static Matrix CreateWorldMatrix(Vector3 Translation,
Matrix Rotation)
{
return CreateWorldMatrix(Translation, Rotation, Vector3.One);
}
// Creates a world matrix
public static Matrix CreateWorldMatrix(Vector3 Translation,
Matrix Rotation, Vector3 Scale)
{
return Matrix.CreateScale(Scale) *
Rotation *
Matrix.CreateTranslation(Translation);
}
In the Camera class:
Projection = Engine.Math.CreateProjectionMatrix(); becomes Projection = MathUtil.CreateProjectionMatrix();
Now change the following in the Actor class:
Matrix world = Engine.Math.CreateWorldMatrix(Position, Rotation, Scale); becomes Matrix world = MathUtil.CreateWorldMatrix(Position, Rotation, Scale);
Rotation = Vector3.Zero; becomes EulerRotation = Vector3.Zero;
Third, representing rotations as a Vector3 is a bad way to do it, for several reasons. Change I3DComponent to look like this:
// Represents a 3D object. These objects will be drawn before
// 2D objects, and will have modifiers automatically provided
// in the editor.
public interface I3DComponent
{
// Position in the Cartesian system (X, Y, Z)
Vector3 Position { get; set; }
// Rotation represented as a Vector3. This shouldn't
// be used for calculations, it is left in so that
// the rotation can be more easily modified by hand
Vector3 EulerRotation { get; set; }
// Rotation as a Matrix. This will give much smoother
// and cleaner calculations that a Vector3
Matrix Rotation { get; set; }
// Scale for each axis (X, Y, Z)
Vector3 Scale { get; set; }
// BoundingBox to use for picking and pre-collision
BoundingBox BoundingBox { get; }
}
Now we need to fix this in a few other classes. Change the following in the Actor class:
// I3DComponent values
public virtual Vector3 Position { get; set; }
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(Rotation); }
set { Rotation = MathUtil.Vector3ToMatrix(value); }
}
public virtual Matrix Rotation { get; set; }
public virtual Vector3 Scale { get; set; }
public virtual BoundingBox BoundingBox
{
get
{
return new BoundingBox(
Position - (Scale / 2),
Position + (Scale / 2)
);
}
}
Now change the following in PhysicsActor:
// Override the rotation of the base class to that
// of the physics object
public override Matrix Rotation
{
get
{
if (PhysicsObject != null)
return PhysicsObject.Rotation;
else
return Matrix.Identity;
}
set
{
if (PhysicsObject != null)
PhysicsObject.Rotation = value;
}
}
Change the Camera class to look like this:
using Microsoft.Xna.Framework;
using System;
using System.Runtime.Serialization;
namespace Innovation
{
// Basic Camera class
public class Camera : Component, I3DComponent
{
// Internal values
Vector3 position = Vector3.Zero;
Matrix rotationMatrix = Matrix.Identity;
Vector3 target = new Vector3(0, 0, -1);
Vector3 up = Vector3.Up;
Matrix view;
Matrix projection;
// The point the camera is looking at
public virtual Vector3 Target
{ get { return target; } set { target = value; } }
// The View and Projection matrices commonly used for rendering
public virtual Matrix View
{ get { return view; } set { view = value; } }
public virtual Matrix Projection
{ get { return projection; } set { projection = value; } }
public virtual Vector3 Up
{ get { return up; } set { up = value; } }
// Public I3DComponent values
public virtual Vector3 Position { get { return position; } set { position = value; } }
public virtual Vector3 Scale { get { return Vector3.One; } set { } }
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(Rotation); }
set { Rotation = MathUtil.Vector3ToMatrix(value); }
}
// The rotation matrix used by the camera and the current up vector
public virtual Matrix Rotation
{ get { return rotationMatrix; } set { rotationMatrix = value; } }
public virtual BoundingBox BoundingBox
{ get { return new BoundingBox(Position - Vector3.One, Position + Vector3.One); } }
// Constructors
public Camera(GameScreen Parent) : base(Parent) { }
public Camera() : base() { }
// Update the camera
public override void Update()
{
// Calculate the direction from the position to the target, and normalize
Vector3 newForward = Target - Position;
newForward.Normalize();
// Set the rotation matrix's forward to this vector
Matrix rotationMatrixCopy = this.Rotation;
rotationMatrixCopy.Forward = newForward;
// Save a copy of "Up" (0, 1, 0)
Vector3 referenceVector = Vector3.Up;
// On the slim chance that the camera is pointed perfectly parallel with
// the Y Axis, we cannot use cross product with a parallel axis, so we
// change the reference vector to the forward axis (Z).
if (rotationMatrixCopy.Forward.Y == referenceVector.Y
|| rotationMatrixCopy.Forward.Y == -referenceVector.Y)
referenceVector = Vector3.Backward;
// Calculate the other parts of the rotation matrix
rotationMatrixCopy.Right = Vector3.Cross(this.Rotation.Forward,
referenceVector);
rotationMatrixCopy.Up = Vector3.Cross(this.Rotation.Right,
this.Rotation.Forward);
this.Rotation = rotationMatrixCopy;
// Use the rotation matrix to find the new up
Up = Rotation.Up;
// Recalculate View and Projection using the new Position, Target, and Up
View = Matrix.CreateLookAt(Position, Target, Up);
Projection = MathUtil.CreateProjectionMatrix();
}
}
}
Change the following in the PhysicsObject class:
// The PhysicsObject's rotation as a Matrix
public Matrix Rotation
{
get { return Body.Orientation; }
set { Body.MoveTo(Body.Position, value); }
}
// The PhysicsObject's rotation as a Euler Vector
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(Rotation); }
set { Rotation = MathUtil.Vector3ToMatrix(value); }
}
Remove the Orientation property from PhysicsObject. Now go through the various physics object, and change any references to Rotation to EulerRotation, and any references to Orientation to Rotation.
« Going on Vacation XNA Game Engine Tutorial Series #7 – First Person Camera »

I’m guessing posting tut 7 was an accident? tut 7 showed in my rss then was gone on your site but now you posted this its back? oh well all the updates are great I’m learning a lot from this series and thanks for all of it.
I posted it forgetting that there were a lot of updates to make, so I took it down, wrote this post, then reposted 7 so that it would work after people made the updates. I’m also in the middle of updating the older posts so new people wouldn’t have to do these ‘update’ posts.
Fantastic tutorials Sean, great to see someone who comments their code seems to be a bit of a lost art. Keep up the great work, very much enjoying reading your stuff, caused me to change the way I have been structuring parts of my own engine.
Also just a quick typo above the projection that needs to be changed to use the MathUtil class is over in Camera not Actor.
Errm, I think in the I2DComponent part, you need to change it to “The Rectangle property needs to be a Rectangle” instead of “needs to be a Vector2″.
Great tuts, btw!
I haven’t followed your series and only came across this article, but it seems you had the engine set up as dynamic classes and are now switching over to static classes.
Especially the idea of keeping the GraphicsDevice in a static field. Is there a particular reason for your decision?
I’m just interested in hearing your motivation
I started out with some static classes, but ultimately went the other way. Mainly because I wanted to use an inversion of control container and because, well, a class which takes a graphics device in its constructor is more easily isolated from the other classes than one depending a static class named X in namespace Y with property Z to exist somewhere in order to compile.
On the other hand, an all-static design might be easier to understand for people new to the topic, so maybe that’s the motivation?