When I'm coding a quick prototype for a game in AS3, at some point I need some placeholder graphics so I end up going to the spriters resource page to "borrow" some pixels.
So I find a Megaman "spritesheet", that is a transparent PNG file with all the frames making up the Megaman animations. Sprite sheets are also called spritemaps, tilemaps, just to clarify.
According to documentation, Flixel creates animations by splitting up images into equal-size squares, loaded by the loadGraphic function in the FlxSprites class). And according to more documentation Flaspunk also uses equal-size squares.
But the spritesheets spriters-resource.com don't usually come as equal-size squares, the frames are generally irregular squares, the size of the square varies for every frame, and the anchor point is not in the center of the square.
This is an example of a spritesheet with equal size squares taken from the FlashPunk tutorials:
(2010 © Tyriq Plummer)
And thatThis is an example of irregular squares:
Therefore if you want to use the spriters-resource.com spritesheets in Flixel or Flashpunk, you’ll need to use photoshop to move around the frames to put them in equal-size rectangles. This might have changed by the time you read this article.
Pesonally, I don’t use those engines, so this tutorial is about animating sprites without an engine. To see those sprites animating on my game I'll need to define the rectangle of each frame, put a name to that sequence, sometimes realign some stuff, create some internal data structure to define the rectangles and the sequences, reference points for position and rotation.
Spritimator s a sprite animating tool developed by William Goddard to help with that: animating sprite frames and spritesheets, defining the rectangle for every frame of the animation, previewing the animations in realtime, putting names to the sequences and exporting all the frames and sequences definitions as XML
You’ll find youtube videos explaining how to use the tool following the link above.
Spritimator generates an XML like this one:
<?xml version="1.0" encoding="UTF-8"?>
<rect Width="34" Height="44" />
<texture File="megamans.png" Width="1024" Height="2048" />
<sequence Name="Running" Return_Loop_Frame="0" Loops="1">
<frame Time="0.08" Tex_X="347" Tex_Y="257" Width="31" Height="78" Anchor_X="15" Anchor_Y="39" Texture="0" />
<frame Time="0.08" Tex_X="383" Tex_Y="257" Width="34" Height="78" Anchor_X="17" Anchor_Y="39" Texture="0" />
<frame Time="0.08" Tex_X="424" Tex_Y="257" Width="40" Height="78" Anchor_X="20" Anchor_Y="39" Texture="0" />
<frame Time="0.08" Tex_X="470" Tex_Y="257" Width="48" Height="78" Anchor_X="24" Anchor_Y="39" Texture="0" />
<frame Time="0.08" Tex_X="526" Tex_Y="257" Width="51" Height="78" Anchor_X="25" Anchor_Y="39" Texture="0" />
<frame Time="0.08" Tex_X="583" Tex_Y="257" Width="43" Height="78" Anchor_X="21" Anchor_Y="39" Texture="0" />
I’ve created the SpritesheetBlitter class to interpret this XML output in AS3 and draw the animation on your screen. The best way to understand it is playing around with the sample code.
Here you can see it working (arrow keys to move lef/right):
The source code comes in two versions: src1_spritimatorParse_load_assets.rar and src2_spritimatorParse_embed_assets.rar
In the first one, the assets are loaded from external files, located in the bin folder. In the second one, the assets are embedded, so it only generates one output file that doesn't need to wait for the load complete event to start drawing things. I'm including a flashdevelop project and an .fla file for you lazy FlashIDE developers :)
The second version does not include the the fla because embedding assets requires the Flex compiler anyway.
You'll notice that the PNG and XML files in my project are the ones that come with the Spritimator tool.
In the version embedding the assets, I've had to change the XML that came with spritimator slightly. To make it work, I had to delete the first line, the <?xml ... ?> header. Otherwise the compiler wouldn't accept it as valid XML (even though it worked in the version that loads the external files)
Going into the source code you'll find just a few classes. SpritesheetBlitter is meant to be a generic reusable class. You’ll need one for each animated character in your game. Then I’ve created a Megaman class that contains one SpritesheetBlitter by composition and implement all the non-reusable code, specific to Megaman, like the way he responds to keyboard events and the way these events change the animations.
In the SpritesheetBlitter class, I've commented out some trace() instructions that are accessing a sequence by name, a sequence frame, the length of a sequence. I’m using E4X features of the XML class. There are really good E4X tutorials out there if you want to understand how to filter and access specific properties of XML data. Uncomment those lines to see the result in your output window. They look like this:
trace("get rect width height:",_animDesc.sprite.rect.@Width, _animDesc.sprite.rect.@Height);
trace("get a sequence by name:",_animDesc.sprite.sequence.(@Name == "Injured"))
trace("get a sequence frame:",_animDesc.sprite.sequence.(@Name == "Injured").frame.toXMLString());
trace("get a sequence length in frames:",_animDesc.sprite.sequence.(@Name == "Injured").frame.length());
If I wanted to add enemies to this sample, I would code an Enemy class containing its own SpritesheetBlitter, loading the enemy’s graphics and animation description XML and implementing the behavior of the enemy in that class.
Another benefit of Spritimator is that it lets you set the duration for each frame, so if you want to make a frame last longer, now it is possible. Taking into account the frame "Time" property we can achive time-based animation (as opposed to frame-based animations). There are many articles about this out there about Time based animation vs frame based animation for games, but for short, the result is consistent animation speed regardless of the CPU speed.
So that's why I'm always passing a timestamp as parameter to many functions. I've no idea how Flixel and Flashpunk handle this.
Another thing to notice is the Anchor Point, that is the reference point to align or center your character along all the frames in an animation sequence. Sometimes the anchor point is your character's feet (on a side scroller game), sometimes the head (in the case of a top view game), sometimes in arbitrary points. That's why is good to have an anchor point as part of the settings. You can change it and preview the changes in Spritimator.
There are many things to improve in the sample, like the character not animating when you press and release the arrow keys quickly instead of leaving the key down. I didn't wanted to complicate the code. Homework for you dear reader.