In this chapter of the tutorial, we will be implementing a physics simulation into our engine! We will not be writing the physics engine ourserlves, however, as that is far too complicated for this series. Instead, we will be writing some classes that are designed to interface with the open source JigLibX physics engine, which is built on XNA. This is great, by the way, because it means that we will be able to maintain compatibility with Xbox.

I have modified the original JigLibX project slightly to make it work better with our engine, and to fix small bugs in the original here and there. We will need to reference this project in our engine project. Download the dll here. Now, open “References” from the project, right click and choose “Add Reference”. Naviagate to the downloaded dll, and choose OK. We now have JigLibX referenced.

Note: If you are interested, you can download the modified JigLibX project here.

Now we need to start integrating JigLibX with our engine. The way this will be setup is as follows:

“Physics” Component: This will be used to manage JigLibX’s “PhysicsSystem” class. It will update the physics simulation and hold the instance of the physics system. We will need to add an instance of “Physics” to the engine’s service container for this to work. However, the benefit here is that if we don’t want to do all the extra phsyics calculations if we aren’t simulating any physics object, then we can simply not add an instance of “Physics” to the engine services.

“PhysicsObject” Component: This is the base type of physics simulation object. It keeps track of the neccessary objects to properly simulate a physical object with JigLibX, and other object types will inherit from it. These types are “Box”, “Capsule”, “Sphere”, “Plane”, and “Triangle Mesh”. The last one simulates every triangle in a model. This is useful for things like levels, which can have a complex design that can’t be simulated with a few boxes and spheres. Another plus here is that we could create new types of physics objects very easily to simulate more complex models without doing work for every triangle.

“PhysicsActor” Component: This component inherits from “Actor”, the key difference being that it takes a PhysicsObject, which is uses for drawing instead of user defined values (like the normal “Actor” class does). It does this by overriding the I3DComponent properties with the position, rotation, scale, and BoundingBox of it’s PhysicsObject.

Lets begin! Add a new class called “Physics”. Set it up as follows:

using JigLibX.Collision;
using JigLibX.Physics;

namespace Innovation
{
    public class Physics : Component
    {
        // The physics simulation
        public PhysicsSystem PhysicsSystem = new PhysicsSystem();

        // Whether or not we should update
        public bool UpdatePhysics = true;

        public Physics()
        {
            // Set up physics system
            this.PhysicsSystem.EnableFreezing = true;
            this.PhysicsSystem.SolverType = PhysicsSystem.Solver.Normal;
            this.PhysicsSystem.CollisionSystem = new CollisionSystemSAP();
        }

        public override void Update()
        {
            // Update the physics system
            if (UpdatePhysics)
                PhysicsSystem.CurrentPhysicsSystem.Integrate(
                    (float)Engine.GameTime.ElapsedGameTime.TotalSeconds);
        }
    }
}

This class will be responsible for handling the JigLibX PhysicsSystem and updating it. If we don’t want to simulate physics in a simpler game, for example, we can not create this class and keep extra calculation to a minimum.

The next class we will build is called PhysicsObject. This is the base class that simulated objects will inherit from. These child classes simulate boxes, capsules (pills), planes, spheres, and triangle meshes (simulate every vertex in a model). Here is the code for this class:

using JigLibX.Collision;
using JigLibX.Collision;
using JigLibX.Geometry;
using JigLibX.Physics;
using Microsoft.Xna.Framework;

namespace Innovation
{
    // Provides a base object type for physics simulation
    public abstract class PhysicsObject : Component, I3DComponent
    {
        // Local copy of the mass of the object
        float mass = 1;

        // The Body managed by the PhysicsObject
        public Body Body;

        // The CollisionSkin managed by the PhysicsObject
        public CollisionSkin CollisionSkin;

        // The mass of the PhysicsObject
        public float Mass
        {
            get { return mass; }
            set {
                // Set the new value
                mass = value;

                // Fix transforms
                Vector3 com = SetMass(value);
                if (CollisionSkin != null)
                    CollisionSkin.ApplyLocalTransform(
                        new JigLibX.Math.Transform(-com, Matrix.Identity));
            }
        }

        // The PhysicsObject's position
        public Vector3 Position
        {
            get { return Body.Position; }
            set { Body.MoveTo(value, Body.Orientation); }
        }

        // 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); }
        }

        // Whether or not the physics object is locked in place
        public bool Immovable
        {
            get { return Body.Immovable; }
            set { Body.Immovable = value; }
        }

        // Returns the PhysicsObject's BoundingBox
        public BoundingBox BoundingBox
        {
            get
            {
                if (Body.CollisionSkin != null)
                    return Body.CollisionSkin.WorldBoundingBox;
                else
                    return new BoundingBox(Position - Vector3.One,
                        Position + Vector3.One);
            }
        }

        // Dummy scale value to satisfy I3DComponent
        public Vector3 Scale
        {
            get { return Vector3.One; }
            set { }
        }

        // The body's velocity
        public Vector3 Velocity
        {
            get { return Body.Velocity; }
            set { Body.Velocity = value; }
        }

        // Constructors
        public PhysicsObject() : base(){ }
        public PhysicsObject(GameScreen Parent) : base(Parent) { }

        // Sets up the body and collision skin
        protected void InitializeBody()
        {
            Body = new Body();
            CollisionSkin = new CollisionSkin(Body);
            Body.CollisionSkin = this.CollisionSkin;
            Body.EnableBody();
        }

        // Sets the mass of the PhysicsObject
        public Vector3 SetMass(float mass)
        {
            PrimitiveProperties primitiveProperties =
                new PrimitiveProperties(
                    PrimitiveProperties.MassDistributionEnum.Solid,
                    PrimitiveProperties.MassTypeEnum.Density, mass);

            float junk; Vector3 com; Matrix it, itCoM;

            CollisionSkin.GetMassProperties(primitiveProperties,
                out junk, out com, out it, out itCoM);
            Body.BodyInertia = itCoM;
            Body.Mass = junk;

            return com;
        }

        // Rotates and moves the model relative to the physics object to
        // better align the model with the object
        public void OffsetModel(Vector3 PositionOffset,
            Matrix RotationOffset)
        {
            CollisionSkin.ApplyLocalTransform(
                new JigLibX.Math.Transform(PositionOffset, RotationOffset));
        }

        // Disables physics body and component
        public override void DisableComponent()
        {
            Body.DisableBody();
            base.DisableComponent();
        }
    }
}

The first type of object we are going to make is a box. We accept the lengths of the sides of the box, and set up the body. As you can see, most of the work is done by PhysicsObject, and most of the code we write here is just various constructor overloads to allow greater flexibility.

using JigLibX.Collision;
using JigLibX.Geometry;
using JigLibX.Physics;
using Microsoft.Xna.Framework;

namespace Innovation
{
    // A box shaped physics object
    public class BoxObject : PhysicsObject
    {
        Vector3 sideLengths;

        // The length of the sides of the box
        public Vector3 SideLengths
        {
            get { return sideLengths; }
            set
            {
                // Set the new value
                sideLengths = value;

                // Update the collision skin
                CollisionSkin.RemoveAllPrimitives();
                CollisionSkin.AddPrimitive(
                    new Box(-0.5f * value, Body.Orientation, value),
                    (int)MaterialTable.MaterialID.UserDefined,
                    new MaterialProperties(0.8f, 0.8f, 0.7f));

                // Set the mass to itself to fix the local transform
                // on the CollisionSkin in the set accessor
                this.Mass = this.Mass;
            }
        }

        // Constructors

        public BoxObject()
            : base()
        {
            InitializeBody();
            SideLengths = Vector3.One;
        }

        public BoxObject(Vector3 SideLengths)
            : base()
        {
            SetupSkin(SideLengths, Vector3.Zero, Vector3.Zero);
        }

        public BoxObject(Vector3 SideLengths, Vector3 Position,
            Vector3 Rotation)
            : base()
        {
            SetupSkin(SideLengths, Position, Rotation);
        }

        public BoxObject(Vector3 SideLengths, Vector3 Position,
            Vector3 Rotation, GameScreen Parent)
            : base(Parent)
        {
            SetupSkin(SideLengths, Position, Rotation);
        }

        // Sets up the object with the specified parameters
        void SetupSkin(Vector3 SideLengths, Vector3 Position,
            Vector3 Rotation)
        {
            // Setup the body
            InitializeBody();

            // Set properties
            this.SideLengths = SideLengths;
            this.Position = Position;
            this.EulerRotation = Rotation;
        }
    }
}

For the sake of brevity, I am not going to post the other physics objects in the post, instead, you can download the code files here:

CapsuleObject.cs
PlaneObject.cs
TriangleMeshObject.cs
SphereObject.cs

Now that we have all these object types, we are going to make a new Actor that knows how to deal with them. We will call this “PhysicsActor”. The difference here is that this class will accept a model and physics object, instead of a position. Most of the work will still be done by the base actor class, but we will be overriding the position, rotation, bounding box, and scale properties to take the physics object’s matching properties. In order to do so, we need to change these properties in the base “Actor” class to “virtual”, which simply means that classes that inherit from “Actor” will be able to override them, or replace their functionality. Change the position, rotation, etc. in the “Actor” class to this:

// I3DComponent values
// 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 add the “PhysicsActor” class. As you can see, all it does is replace the values of position, rotation, etc. to those of the physics object, and does some management of the object.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Innovation
{
    // Manages a PhysicsObject and allows the engine to work
    // with it
    public class PhysicsActor : Actor
    {
        // The object we are managing
        public PhysicsObject PhysicsObject;

        // Override the position of the base class to that
        // of the physics object
        public override Vector3 Position
        {
            get {
                if (PhysicsObject != null)
                    return PhysicsObject.Position;
                else
                    return Vector3.Zero;
            }
            set
            {
                if (PhysicsObject != null)
                    PhysicsObject.Position = value;
            }
        }

        // 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;
            }
        }

        // Override the BoundingBox of the base class to that
        // of the physics object
        public override BoundingBox BoundingBox
        {
            get {
                if (PhysicsObject != null)
                    return PhysicsObject.BoundingBox;
                else
                    return new BoundingBox(-Vector3.One, Vector3.One);
            }
        }

        // Constructors

        public PhysicsActor(Model Model, PhysicsObject PhysicsObject)
            : base(Model, PhysicsObject.Position)
        {
            this.PhysicsObject = PhysicsObject;
        }

        public PhysicsActor(Model Model, PhysicsObject PhysicsObject,
            GameScreen Parent)
            : base(Model, PhysicsObject.Position, Parent)
        {
            this.PhysicsObject = PhysicsObject;
        }

        // Override DisableComponent so we can remove the physics
        // object as well
        public override void DisableComponent()
        {
            this.PhysicsObject.DisableComponent();
            base.DisableComponent();
        }
    }
}

We are now done with our basic physics implementation! Now let’s change our demo game so we can test it out! Here is the updated content for this tutorial: Content.zip.

To demo our physics, we are going to create a stack of boxes, then knock it down with another box after a few seconds. Change the load method to look like the following code. Here we are doing all the regular set up stuff, but we are also adding a Physics component, and creating a plane for the ground, and creating the pile of boxes.

protected override void LoadContent()
{
    // Setup engine. We do this in the load method
    // so that we know graphics will be ready for use
    Engine.SetupEngine(graphics);

    // Create a new Camera
    Camera camera = new Camera();

    // Setup its position and target
    camera.Position = new Vector3(3, 3, 5);
    camera.Target = new Vector3(0, 0, 0);

    // Add it to the service container
    Engine.Services.AddService(typeof(Camera), camera);

    // Setup physics
    Engine.Services.AddService(typeof(Physics), new Physics());

    // Create the plane and make it immovable
    PhysicsActor plane = new PhysicsActor(
        Engine.Content.Load<Model>("Content/ig_plane"),
        new BoxObject(new Vector3(4, .01f, 4)));
    plane.PhysicsObject.Immovable = true;

    // Load the model we will use for our boxes
    Model model = Engine.Content.Load<Model>("Content/ig_box");

    // Create the stack of boxes
    for (int y = 0; y < 3; y++)
        for (int x = 0; x < 3; x++)
        {
            PhysicsActor act = new PhysicsActor(model, new BoxObject(
                new Vector3(.5f),
                new Vector3(- .5f + (x * 0.52f), .5f + (y * 0.52f), -1),
                Vector3.Zero));

            act.Scale = new Vector3(.5f);
        }
}

Now create a variable of type bool called fired, then update the update method (get it? funny right? ha ha ha). The “fired” boolean will keep track of whether or not we have launched our box. After two seconds have passed according to XNA’s GameTime, we will shoot a box at the pile.

bool fired = false;

protected override void Update(GameTime gameTime)
{
    // Update the engine and game
    Engine.Update(gameTime);

    if (gameTime.TotalGameTime.TotalSeconds > 2 && !fired)
    {
        PhysicsActor act = new PhysicsActor(
            Engine.Content.Load<Model>("Content/ig_box"),
            new BoxObject(new Vector3(1), new Vector3(0, .5f, 1), Vector3.Zero));

        act.Scale = new Vector3(1);
        act.PhysicsObject.Mass = 1000;
        act.PhysicsObject.Velocity = new Vector3(0, 2, -6);

        fired = true;
    }

    base.Update(gameTime);
}

Run the game (F5), and you should see the pile of boxes get knocked over!

Congratulations, we have successfully built physics into our engine! In the future, our components will be able to take advantage of this and simulate physics of their own. Make sure you understand how everything works so far, because it’s important that you have a good understanding of our engine’s structure. See you next time, and don’t be afraid to ask questions in the comments if you need help!

Download the Code for this Chapter

Back to Game Engine Tutorial Series

« »