2D

2D Pie Drawing updated to 4.0

UberGeekGames just provided me with an version of the Pie Drawing sample, updated to XNA 4.0

You can find it on the sample’s page, or download it directly from here.

Enjoy!

2dshadowmaps2009100123404079.png

Adding softness to shadows

In my efforts to make the shadows soft, based on the formulas for penumbras, I finally realized that my method does not support physically correct penumbra softness, but I will explain the reason for this when I do the tutorial.

Until then, here’s what I came up with, after applying some Gaussian blur to the final shadow image. (variable degree of softness)

2dShadowMaps 2009-10-01 23-40-40-79

2dShadowMaps 2009-10-01 23-41-11-51

Even if it’s not physically correct, I still think the softness looks good enough.

There’s also an interesting looking result when the radius of the Gaussian Blur depends on the distance from the light…

2dShadowMaps 2009-10-02 00-01-58-45

Working on shadows…

Those that follow my twitter account have seen this already, but I wanted to let everyone know I’m working on a system for 2D dynamic shadows, again.

However, this one is very different from the last sample I made on the subject. In that one, you had to define the geometry of the shadow casters, and build the shadows based on that. This process also implied lots of computations done each frame on the CPU, which yielded in low peformance. So all in all, even though it looked great, I was never really satisfied with tat technique for shadows.

I spent a lot of time thinking of an alternative way to do dynamic 2D shadows, while not using the CPU too much, and having unlimited complexity for the shadow casters. And two weeks ago, the idea hit me. I’m not going to go into technical details just yet, since I plan to make a nice tutorial about this, but I can say that my idea was based on taking the concept of shadow maps from 3D and somehow use it in 2D.

Here’s two pictures of how it looks so far:

first version

second version

As you can see, the casters can have any shape and complexity, and furthermore, the complexity of the shadow casters has no effect on the framerate.

I’m still working on this, but you’ll know as soon as it’s done.

catwalk.png

Loading ToonBoom animations in XNA

Last time, I talked about my experience with drawing and animating 2D images with ToonBoom. In the end of that post, I said that one way to load ToonBoom animations in XNA was to export the animation as a sequence of images, and then load these images and animate them in XNA. So today we will look at a quick way to to just that.

The exporting part is easy enough: just user File->Export Movie in ToonBoom, and then select Image Sequence as the Export Format. The result will be a collection of images, depending on the framerate you choose. The result from my cat animation can be seen in this archive.

The next step is assembling all the images in a single image, usually called a sprite-sheet. Of course, you could also simply load all the images as they are in several Texture2D variables, but working with sprite-sheets yields better performance. For the creation of the sprite-sheet, there are several options.

The first one is to open an image processing application, load all small images, and assemble them in a single image manually. You can imagine this is time consuming, and only worthy if you plan on doing this operation for a very small number of sprites.

The second option, which I used for this sample, is to write a small program that takes the images as input, and generates the sprite-sheet as you want it. My version of this was quickly hacked in a few minutes, so you can see from the source code (get it here) that it makes several assumptions:

  • all input images are the same size, and are rectangular
  • the output sprite will contain all input sprites arranged on a single row
  • the input files are all named similarly (cat1.png, cat2.png, …, cat14.png)

While definitely not an elegant solution, it did it’s job, and I was quickly able to obtain the following image (click for larger size):

catWalk

The third option, which is the recommended one for a larger project, is to use a more complex program for creating sprite-sheets. You can either create one yourself, based on certain file formats you want to use internally, or around certain restrictions you want to impose on your engine; or you can use an existing one, such as Ziggyware’s Sprite Sheet Creator. Note that if you go for this option, you’ll have to follow certain conventions in your runtime code, imposed by your program used for creating the sprite-sheets.

That being said, we now have a sprite sheet with all the frames of the walking cat animation, and are ready to load this in XNA.

After creating a new XNA project, I read through Nick’s article about Sprite Sheet Animations, and created the following class to hold all information needed for animations. For a detailed explanation, go ahead and read Nick’s article.

   1: class Animation

   2: {

   3:     Rectangle[] frames;

   4:     float frameLength = 1f / 5f;

   5:     float timer = 0f;

   6:     int currentFrame = 0;

   7:  

   8:     /// <summary>

   9:     /// Gets of sets the FPS of the animation

  10:     /// </summary>

  11:     public int FramesPerSecond

  12:     {

  13:         get { return (int)(1f / frameLength); }

  14:         set { frameLength = 1f / (float)value; }

  15:     }

  16:  

  17:     /// <summary>

  18:     /// Gets the Rectangle containing the current frame of animation

  19:     /// </summary>

  20:     public Rectangle CurrentFrame

  21:     {

  22:         get { return frames[currentFrame]; }

  23:     }

  24:  

  25:     /// <summary>

  26:     /// Creates an animation object

  27:     /// </summary>

  28:     /// <param name="width"> the total width of the input image</param>

  29:     /// <param name="height"> the height of the input image</param>

  30:     /// <param name="numFrames"> the number of frames in the sprite-sheet</param>

  31:     /// <param name="xOffset"> the X origin of the sprite-sheet</param>

  32:     /// <param name="yOffset"> the Y origin of the sprite-sheet</param>

  33:     public Animation(int width, int height, int numFrames, int xOffset, int yOffset)

  34:     {

  35:         frames = new Rectangle[numFrames];

  36:         int frameWidth = width / numFrames;

  37:         for (int i = 0; i < numFrames; i++)

  38:         {

  39:             frames[i] = new Rectangle(xOffset + (frameWidth * i), yOffset,

  40:                                       frameWidth, height);

  41:         }

  42:     }

  43:  

  44:     /// <summary>

  45:     /// update the animation

  46:     /// </summary>

  47:     /// <param name="elapsed"> seconds since the last frame</param>

  48:     public void Update(float elapsed)

  49:     {

  50:         timer += elapsed;

  51:  

  52:         if (timer >= frameLength)

  53:         {

  54:             timer = 0f;

  55:             currentFrame = (currentFrame + 1) % frames.Length;

  56:         }

  57:     }

  58:  

  59:     /// <summary>

  60:     /// resets the animation

  61:     /// </summary>

  62:     public void Reset()

  63:     {

  64:         currentFrame = 0;

  65:         timer = 0f;

  66:     }

  67:  

  68: }

Next, I created a class for the cat, holding a few members we need for the animation.

   1: class Cat

   2: {

   3:     Texture2D texture;              //sprite-sheet containing the cat animation

   4:     Animation walkingAnimation;     //animation object used for animating

   5:     Vector2 velocity;               //movement direction

   6:     float movementSpeed;            //movement speed

   7:     Vector2 origin;                 //origin of the image

   8:     bool isMirrored = false;        //draw the image mirrored

   9:  

  10:     public Vector2 Position { get; set; }   //position on the screen

Nothing really special here… Maybe except the isMirrored variable. We use this because our image for the cat shows it facing left. So when we want it to move towards the right, rather than creating a separate sprite with the cat facing right, we mirror the existing sprite. Of course, you can’t always use this trick (or a right-handed character suddenly becomes left-handed), but there are many cases when this trick is enough.

The constructor is straightforward, with some hard-coded values tweaked until I was satisfied with how things looked.

   1: public Cat(Texture2D texture, int frameCount, Vector2 origin)

   2: {

   3:     this.texture = texture;

   4:     //create a new animation object

   5:     walkingAnimation = new Animation(texture.Width, texture.Height, frameCount, 0, 0);

   6:  

   7:     //tweak the FramesPerSecond and movementSpeed values until you're satisfied with how things move

   8:     walkingAnimation.FramesPerSecond = 14 * 3;

   9:     movementSpeed = 256;

  10:  

  11:     //reset position

  12:     Position = Vector2.Zero;

  13:  

  14:     this.origin = origin;

  15: }

For movement, input from both keyboard and gamepad is analyzed, and the velocity’s value is updated.

   1: public void HandleInput()

   2:     {

   3:         KeyboardState keyState = Keyboard.GetState();

   4:         GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);

   5:  

   6:         velocity = Vector2.Zero;

   7:  

   8:         if (gamepadState.IsConnected)

   9:         {

  10:             velocity = gamepadState.ThumbSticks.Left;

  11:             velocity.Y *= -1;

  12:         }

  13:  

  14:         if (keyState.IsKeyDown(Keys.Left))

  15:             velocity.X = -1.0f;

  16:         if (keyState.IsKeyDown(Keys.Right))

  17:             velocity.X = 1.0f;

  18:         if (keyState.IsKeyDown(Keys.Up))

  19:             velocity.Y = -1.0f;

  20:         if (keyState.IsKeyDown(Keys.Down))

  21:             velocity.Y = 1.0f;

  22:     }

In the Update function, we first look which way the cat is facing, and update the value of isMirrored. Then, if the cat is moving, we update the animation and position on the screen.

   1: public void Update(GameTime gameTime)

   2:     {

   3:  

   4:         //mirror the cat if we are moving towards the right

   5:         if (velocity.X > 0.1f)

   6:             isMirrored = true;

   7:         if (velocity.X < -0.1f)

   8:             isMirrored = false;

   9:  

  10:         //normalize velocity vector

  11:         if (velocity.Length() > 1.0f)

  12:             velocity.Normalize();

  13:  

  14:         //get elapsed seconds

  15:         float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

  16:  

  17:         //only animate if we are moving

  18:         float speed = velocity.Length();

  19:         if (speed > 0.0f)

  20:             walkingAnimation.Update(elapsed * speed);

  21:  

  22:         //update position

  23:         Position += velocity * elapsed * movementSpeed;

  24:     }

Finally, the Draw function takes as a parameter the active spriteBatch, and draws the current animation frame using it. Here we can see how to mirror the sprite using SpriteEffects.FlipHorizontally.

   1: public void Draw(SpriteBatch spriteBatch)

   2:     {

   3:         SpriteEffects spriteEffect = SpriteEffects.None;

   4:  

   5:         //mirror the image if necessary

   6:         if (isMirrored)

   7:             spriteEffect = SpriteEffects.FlipHorizontally;

   8:  

   9:         spriteBatch.Draw(texture, Position, walkingAnimation.CurrentFrame,

  10:                         Color.White, 0.0f, origin, 1.0f, spriteEffect, 1.0f);

  11:     }

With this class created, using it in our Game class is trivial. Simply load the texture in LoadContent() and create a Cat object, update it’s input and internal state in Update() and draw it in Draw().

   1: public class Game1 : Microsoft.Xna.Framework.Game

   2: {

   3:     GraphicsDeviceManager graphics;

   4:     SpriteBatch spriteBatch;

   5:     Cat cat;

   6:  

   7:     public Game1()

   8:     {

   9:         graphics = new GraphicsDeviceManager(this);

  10:         Content.RootDirectory = "Content";

  11:     }

  12:  

  13:     protected override void LoadContent()

  14:     {

  15:         spriteBatch = new SpriteBatch(GraphicsDevice);

  16:  

  17:         //load cat texture

  18:         Texture2D catTexture = Content.Load<Texture2D>("catWalk");

  19:  

  20:         //create cat object

  21:         cat = new Cat(catTexture,14,new Vector2(64,128));

  22:  

  23:         //place it in the center of the screen

  24:         cat.Position = new Vector2(400, 300);

  25:     }

  26:  

  27:     protected override void Update(GameTime gameTime)

  28:     {

  29:         // Allows the game to exit

  30:         if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)

  31:             this.Exit();

  32:  

  33:         //update cat's input

  34:         cat.HandleInput();

  35:         //update cat's state

  36:         cat.Update(gameTime);

  37:  

  38:         base.Update(gameTime);

  39:     }

  40:  

  41:     protected override void Draw(GameTime gameTime)

  42:     {

  43:         GraphicsDevice.Clear(Color.CornflowerBlue);

  44:  

  45:         spriteBatch.Begin();

  46:         //draw cat

  47:         cat.Draw(spriteBatch);

  48:         spriteBatch.End();

  49:  

  50:         base.Draw(gameTime);

  51:     }

  52: }

If you run the game now, you’ll be able to move the cat around the screen with the keyboard or the mouse. As you can see, getting an animation from ToonBoom into an XNA game is not difficult at all.

I hope you enjoyed this short post, and if you did, you can download the source for this sample here: ToonBoomAnimationSample.zip

videosample2009061121380488.jpg

New Sample: XNA GS 3.1 Video Support

You probably heard by now that XNA Game Studio 3.1 is out.

After a quick download, uninstalling 3.0 and installing 3.1, I quickly put together this sample that shows how to use the new support for videos.

More info on the sample’s page, here.

VideoSample 2009-06-11 21-38-04-88

Or, if you’re in a hurry, here’s the direct link to the download: VideoSample.zip

goocursor2009012600393055.jpg

World of Goo Cursor sample

As an exception, I will post the sample for now, and come back with the informative and explanatory blog post in a few days, since my exams don’t allow me too much XNA work at once.

So the first sample deals with the XNA implementation of something similar to the mouse cursor encountered in World of Goo. My blog post later this week will contain more information about how I built the sample, but until then, you can try it out, and play with it.

To download it, access the sample’s page, here.

 GooCursor 2009-01-26 00-39-30-55 GooCursor 2009-01-26 00-36-14-92

Have fun toying with the configurable parameters! :)

depthrecovery-2008-05-19-02-30-51-86.jpg

Can a 2D image intersect a 3D model?

Yes it can :)

My may sample is also my first public sample written in XNA Game Studio 3.0 CTP, and it shows how to restore the depth buffer from a depth texture.

This way, models drawn to a render target, with post processing applied to them can intersect and obscure normal models, drawn after all the post processing is done.

For more details, jump to the sample’s page: Restoring the Depth Buffer, where you can find a short explanation on how the sample works.

To dive right into the code, download it here. Please note that the sample is written in XNA Game Studio 3.0 CTP, but the technique also works just fine in 2.0.

DepthRecovery 2008-05-19 02-30-51-86

dynamicshadows3.jpg

April Sample Online!

I finally finished the April sample. I know it’s May already but the MVP Summit and the Easter Holiday took most of this month :)

So for April we have Dynamic 2D Shadows. Check it out in the Samples section, and let me know what you think. Or download it directly, here.

I hope you will enjoy this sample.

DynamicShadows3