Fun with XNA and 2.5D

20 Dec

This weekend I had a little fun in XNA playing with the concept of 2.5D.  There are a number of things games use that can be called 2.5D – I choose to build a test project where all draw calls were in 2D, but it is also common to use 2D sprites in 3D space as well.  These sprites are referred to as billboards, and there is an example project for using them in XNA at the App Hub site.

For my project, I wanted to photograph an object from multiple sides, convert this to a sprite sheet, and then render the correct side based on the direction the object was facing.  I talked about this idea with my two oldest daughters, and asked for suggestions on the object I should use.  I fully expected a debate to involve Legos or stuffed animals, but they both wanted to use themselves!  Using the green screen I have for GameMarx, and a set of swords I have from this thing I used to do, we setup the shoot.  I had the girls stand on an ottoman so I could rotate them p/4 each shot (all game devs think in radians eventually):


Next I took these shots and converted them into a sprite sheet, making sure to keep them in order so it will be easier later in code to manage:


In code, I created an array to hold the location of each sprite on the sheet.  For simplicity, I’m only going to post the code for Hannah – Rachel’s code is pretty much the same with the only difference being the start locations.  I found it easier to have the first direction facing up, so I listed the second row for Hannah first:

Rectangle[] hannah = new Rectangle[] {
    new Rectangle(0, 128, 128, 128),
    new Rectangle(128, 128, 128, 128),
    new Rectangle(256, 128, 128, 128),
    new Rectangle(384, 128, 128, 128),
    new Rectangle(0, 0, 128, 128),
    new Rectangle(128, 0, 128, 128),
    new Rectangle(256, 0, 128, 128),
    new Rectangle(384, 0, 128, 128),

In the game loop update, I need to figure out from the player’s thumbstick what direction to move Hannah, and also which sprite to display.   Movement is pretty straight forward, I just take the X and Y of the thumbstick as is. 

To calculate the sprite, I first need to calculate the angle of the thumbstick, using the Atan2 method.  Atan2 will return a value from -p to p, so to make it easier on myself I add p so that I have a range from 0 to 2p.  I then scale this result to the number of sprites for Hannah and offset it slightly by p/8.  Why do the offset?  Well, if I didn’t straight up would be zero, but slightly to the right would be just under 7 (we have 8 values, 0 through 7).  We want the have an even +/- p/8 to the direction on the stick so that Hannah heads in the direction players expect.

The final step is to check an see if we need to wrap the high end back to zero, or undo our previous adjustment since it cuts off a few values for zero.  The end result looks like:

if (controller.ThumbSticks.Left.Length() > .2) {
    hannahLoc.X += Convert.ToInt32(controller.ThumbSticks.Left.X * speed * gameTime.ElapsedGameTime.TotalSeconds);
    hannahLoc.Y -= Convert.ToInt32(controller.ThumbSticks.Left.Y * speed * gameTime.ElapsedGameTime.TotalSeconds);
    hannahAgl = Math.Atan2(controller.ThumbSticks.Left.X, -1 * controller.ThumbSticks.Left.Y) + MathHelper.Pi;
    double face = (hannahAgl + MathHelper.PiOver4 / 2) * (hannah.Length - 1) / MathHelper.TwoPi;
    hannahFace = Convert.ToInt32(face > 7.25 || face < .75 ? 0 : Math.Round(face));

And the draw call is simply:

spriteBatch.Draw(spriteSheet, hannahLoc, hannah[hannahFace], Color.White);

To see all this in action, I made a quick youtube video: