Skip to content
March 15, 2010 / uglabs

Source Code For Sprite Sheet Animator

One of the essential parts of the game, of any game, is animations. They make a huge difference between the regular games and the better ones, in most cases. So I thought it would be nice to put out a very simple sprite sheet class, and an extension which allows you to have more control over it. Of course, I expect you to add onto the class, which is why it is so robust, lacking many basic features such as gotoAndStop or gotoAndPlay or even rewind. You could even change it so you can control the playback rate if you were so inclined to.

Instead of making my own sprite sheet class first, I went and did some research on them just to see if there was a simple 1 class handler. I found one that worked quite well. I ended up modifying it to make it a bit more fast, handling around 50% or so more sprites at around the same speed, by reducing the number of bitmaps being created. Below is the full source code!

//Modified and extends by UnknownGuardian
//Credit from http://www.bensilvis.com/?p=317

package ugLabs.graphics
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    public class SpriteSheet extends Sprite
	{

        private var tileSheetBitmapData:BitmapData;
        private var canvasBitmapData:BitmapData;

        private var tileWidth:int;
        private var tileHeight:int;
        private var rowLength:int;

        private var tileRectangle:Rectangle;
        private var tilePoint:Point;

        public function SpriteSheet(tileSheetBitmap:Bitmap, width:Number = 16, height:Number = 16)
        {
            tileSheetBitmapData = tileSheetBitmap.bitmapData;
            tileWidth = width;
            tileHeight = height;

            rowLength = int(tileSheetBitmap.width / width);

            tileRectangle = new Rectangle(0, 0, tileWidth, tileHeight);
            tilePoint = new Point(0, 0);

            canvasBitmapData = new BitmapData(tileWidth, tileHeight, true);
            var canvasBitmap:Bitmap = new Bitmap(canvasBitmapData);
            addChild(canvasBitmap);

            drawTile(0);
        }

        public function drawTile(tileNumber:int):void
        {
            tileRectangle.x = int((tileNumber % rowLength)) * tileWidth;
            tileRectangle.y = int((tileNumber / rowLength)) * tileHeight;
            canvasBitmapData.copyPixels(tileSheetBitmapData, tileRectangle, tilePoint);
        }

    }
}

What is so nice about this class? To switch to a different frame, just call drawTile(frameNumber). Very simple. No extra addons, or complicated code.

Then to animate it, I also custom made this class which will play the animation automatically for you at the speed of your .swf, making one drawTile() call per frame.

//Created by UnknownGuardian
//Extends a modified package

package ugLabs.graphics
{
	import flash.display.Bitmap;
	import flash.events.Event;
	/**
	 * ...
	 * @author UnknownGuardian
	 */
	public class SpriteSheetAnimation extends SpriteSheet
	{
		public var frameNumber:int = 0;
		public var numFrames:int = 0;
		public var isAdded:Boolean = false;
		public var destroyWhenComplete:Boolean = false;

		public function SpriteSheetAnimation(tileSheetBitmap:Bitmap, Width:Number, Height:Number, numberOfFrames:int , startImmediately:Boolean, destroyOnComplete:Boolean ):void
		{
			super(tileSheetBitmap, Width, Height);

			numFrames = numberOfFrames;
			destroyWhenComplete = destroyOnComplete;

			if (startImmediately)
			{
				addEventListener(Event.ENTER_FRAME, animate);
				isAdded = true;
			}
		}
		public function startAnimation():void
		{
			if (!isAdded)
			{
				addEventListener(Event.ENTER_FRAME, animate);
				isAdded = true;
			}
		}
		public function animate(e:Event):void
		{
				drawTile(frameNumber);

				frameNumber++;
				if (frameNumber == numFrames)
				{
					frameNumber = 0;
					if (destroyWhenComplete)
					{
						destroy();
					}
				}
		}
		public function destroy(e:Event = null):void
		{
			if (parent != null)
			{
				parent.removeChild(this);
				if (!isAdded)
				{
					removeEventListener(Event.ENTER_FRAME, animate);
					parent.removeChild(this);
				}
			}
		}
	}

}

All you have to do is put these in a directory called ugLabs -> graphics -> .as files, or you can rename the package name and put it into your own custom class library and distribute it/use it however you want. Please do keep the credit code at the top to the original source code found at bensilvis.com.

Now, how do we get started? What method do I call?

Simple again!

//explosionSheet is a predefined bitmap
//110 is the animation's height, not the bitmap's
//100 is the animation's width, not the bitmap's
//31 is the number of frames in your animation
//the first boolean paramater is true to start immediately
//second boolean parameter is true to destroy on completion of animation

var g:SpriteSheetAnimation = new SpriteSheetAnimation(new explosionSheet(), 110, 100, 31, true, true);
addChild(g);

Answers to common questions

  • Works when rotated
  • Works when scaled
  • Handles any size, shape of sprite sheet.

It handles any size, shape of sprite sheet? Are you sure?

Yes, it doesn’t care if you have empty slots, as long as you tell it the correct number of frames. However, the frames must be in order with no blank slots unless you want a flickering animation. They also can be in a single row, or a single column. It doesn’t care, so why should you? One of our sheets is 3000 pixels tall, and it renders it just fine.

If you have any questions, fell free to leave a comment.

Cheers,

UnknownGuardian

Advertisements

6 Comments

Leave a Comment
  1. Jonathanasdf / Mar 15 2010 5:40 pm

    It handles any size, shape of sprite sheet? Are you sure?
    Man I’ve waited for something that can handle a circular sprite sheet with circular sprites forever!

    Jokes aside, a nice add-on feature to have would be a gotoAndStop and gotoAndPlay feature! To support this feature you would have to be able to register functions or callbacks with specific frames that would be triggered as you reach that frame. You can then replay certain sections of the spritesheet and thus have 1 spritesheet contain more than 1 type of animation so you won’t have to switch between different spritesheets. And as a bonus it can double as an event dispatcher once implemented.

    This is easily doable so I look forwards to this new feature in the near future 🙂

  2. uglabs / Mar 15 2010 6:06 pm

    Good point. I’m going to make that “any regular rectangular shape”. Is that good enough? And how would one have a circular shaped sprite sheet? I’m only aware of rectangular shaped saving techniques. Please do let me know when one comes out, and I will try to implement it, haha.

    And Jonathan, I left the implementation of a gotoAndStop as well as a gotoAndPlay method(s) up to you. However, I may relent and release a version with these capabilities. Though so far, they are unneeded in Spin the World.

    Thanks!

  3. Tadej / Apr 26 2010 5:02 am

    Thanks for the post – helpful!

  4. Anonymous / May 10 2010 7:18 am

    Was searching for this, but I could only find the Ben Silvis “animation coming soon”. Good thing I found this link from your Kongregate post.

  5. uglabs / May 10 2010 9:30 am

    Great! I hope its useful. You can always modify/extend onto it if you want.

  6. Vieko Franetovic / Sep 14 2010 1:25 pm

    I salute you sir. Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: