Code Samples

Here's where you can find some of my code samples, as well as a description of what they do, and maybe why I made them. Forgive the cramped quarters of this blog space, I'll be formating my code so it fits within the confines of the boxes on screen without wrap around. Code examples are divided in the links below by language type.

ActionScript 3
Flixel Animation






Flixel Animation (ActionScript3, Flixel)
Flixel is an amazing little library for making games within Flash. However, for Falling I needed the animation system to be slightly more robust, but without messing around with the way Flixel already worked too much.

What it did: The way Flixel is set up is an animations' frames are an array of integers, with each animation having a seperate array of frames. So for instance, Running might be frames 5-20. When the player starts running, it would start the animation, and draw frame number 5 from the character sheet to the screen, simple and straight forward.

What I needed: I needed an animation system with an adjustable anchor point, specifically for the player's pulling up animations from hanging, as well as an easy way to adjust the bounding box of the player based off of his actions. For instance when I wanted to crouch, the current system in flixel had me calling the state change to crouch, resizing the bounding box of the player, and then offsetting the player's position based off of the adjusted bounding box.

What I did: I decided to make a frame object (FlxFrame to fit with the naming convention) that each animated FlxSprite object (for instance, the player) would have an array of contained within them. The Flixel animation system would still use an integer to tell what frame to draw, but instead of going directly to the sprite sheet and drawing the frame at the coordinates it figured out, it uses that integer to select that part of the array.

However, the first thing that needed to happen was FlxSprite needed to access it's new array of frames, and fill it. The old GenFrames function was used to create frames for the opposite facing direction, and add them to the character sheet in a manner that they could still be numerically accessed like the other frames. this functionality is all still in place, however now upon figuring out if you want flipped frames or not, it creates an empty array of flxFrame objects with the estimated frames.

/**
* Private function that initializes all the offsets
* for all frames of animation
* TG - 	edited function to fill the new flxFrame array.
*	added parameter for frame count.
* @param   Count   The number of frames on the sprite sheet.
*/
private function GenFrames(Count:uint = 0):void 
{
	var totalFrames:uint = _flipped?(Count * 2):Count;
	for (var i:int = 0; i < totalFrames; ++i)
	{				
		var rx:uint = (i >= Count)?(i - Count):i;
		
		// set the x position on the sprite sheet
		rx *= frameWidth;
						
		// default the y position to 0 (top of the sheet)
		var ry:uint = 0;				
		
		// set w to the width of the loaded image
		// or set it to the value of flipped.		
		var w:uint = _flipped?_flipped:_pixels.width;	
		
		//error handling from the original code.		
		if(rx >= w)			
		{
			ry = uint(rx/w)*frameHeight;	
			rx %= w;			
		}
				
		//handle reversed sprites
		if (_flipped && (i >= Count))			
		{	
			rx = (_flipped << 1) - rx - frameWidth;	
		}
		
		//forgive this long function call...
		//blog formatting only makes it look worse.
		_frames.push(new FlxFrame(new Rectangle
					(rx,ry,frameWidth, frameHeight),
					 new FlxPoint
					(offset.x, offset.y)));
	}
}

The new setup can still set up frames like it used to pretty easy. Unfortunately, if you want all the extra bells and whistles of the new frames, you're gonna have to feed it that information yourself. so that's why there are the FillAllFrames, and FillMultipleFrames functions. I might add a FillFrame function, but it just seemed kind of pointless. Anyways, FillAllFrames... does exactly that, it fills all the frames with the passed in parameters, if you want flipped frames, it does that too. FillMultipleFrames will fill a series of frames (for instance 4-10) within the array, it will also handle flipped frames for you as well. So you have  1 or 2 more function calls to make when the object is initialized, but then it's all good.

/**
 * Recursive function used on my blog for 
 * when an AS3 code example isn't available.
 */
private function WaitForIt()
{
	//The example doesn't exist yet, so...
	trace("Wait for it....");
	WaitForIt();
}

Last but not least, the calcFrame function. UpdateAnimation doesn't really need to be touched because all it does is check the current values. However, in calcFrame, we actually change the frame, and apply the new frames values TO the current values, which is what updates the bounds, delay, actual drawn frame, and anchor point.

/**
* Internal function to update the current animation frame.
* TG -	Changed the function to flip through the new flxFrame Array.
* 	Applies changes to offset and bounding box.
*/
protected function calcFrame():void
{
			
	var fcaf:uint = 0;

	// set the x position on the sprite sheet
	var rx:uint = _caf * frameWidth;

	// default the y position to 0 (top of the sheet)
	var ry:uint = 0;									

	//Handle sprite sheets
	var w:uint = _flipped?_flipped:_pixels.width;
	
	// if rx is greater than w		
	if(rx >= w)	
	{					
		// find the y position in the sprite sheet	
		ry = uint(rx/w)*frameHeight;
		
		// get the new x positon		
		rx %= w;
	}
			
	//handle reversed sprites
	if (_flipped && (_facing == LEFT))
	{	
		fcaf = _caf + (_frames.length / 2);
		_caf = fcaf;			
	
		// offset the x position to the flipped sprite
		rx = (_flipped << 1) - rx - frameWidth;		
	}
			
	//Update display bitmap
	if (_frames[_caf])
	{
		_flashRect.x = _frames[_caf].frame.x;
		_flashRect.y = _frames[_caf].frame.y;
		offset = _frames[_caf].anchor;
		width = _frames[_caf].boundWidth;
		height = _frames[_caf].boundHeight;
	}
	
	_framePixels.copyPixels(_pixels,_flashRect,_flashPointZero);
	_flashRect.x = _flashRect.y = 0;
	if(_ct != null) _framePixels.colorTransform(_flashRect,_ct);
	if(FlxG.showBounds)
		drawBounds();
	if(_callback != null) _callback(_curAnim.name,_curFrame,_caf);
}

Now all that's left is the FlxFrame Object itself. Each flxFrame contains it's own "frame" (The rectangle to draw to screen), bounds (The bounding box of the frame), a delay (how long this frame is displayed), and an anchor (used for positioning the sprite).

package org.flixel.data 
{
	import flash.geom.Rectangle;
	import org.flixel.FlxPoint;
	/**
	 * The "frame" class for all animations. Adds anchor points for 
	 * animation as well as a per frame delay, without changing the
	 * way animations are implemented too much.
	 */
	public class FlxFrame
	{
		/**
		 * NOTE: itended to be read only! may cause unexpected 
		 * results 
		 * The rectangle that makes up the frame
		 */
		public var frame:Rectangle;
		
		/**
		 * NOTE: itended to be read only! may cause unexpected
		 * results! 
		 * The anchor point of the frame
		 */
		public var anchor:FlxPoint;
		
		/**
		 * NOTE: itended to be read only! may cause unexpected
		 * results 
		 * The delay time for the frame 
		 */
		public var delay:Number;
		
		/**
		 * NOTE: itended to be read only! may cause unexpected
		 * results 
		 * The bounding box width
		 */
		public var boundWidth:Number;
		
		/**
		 * NOTE: itended to be read only! may cause unexpected
		 * results 
		 * The bounding box height
		 */
		public var boundHeight:Number;
		
		
		public function FlxFrame(f:Rectangle = null, 
					 a:FlxPoint = null, d:Number = 0) 
		{
			if (f && f.width && f.height) 
				frame = f;
			else
				frame = new Rectangle(0, 0, 32, 32);
			
			if (!a)
			{
				anchor = new FlxPoint(16, 32);
			}
			else
				anchor = a;
				
			delay = d;
		}
		
	}

}

And that about sums everything up! some final little notes...

Drawbacks? well frames take up a bit more memory now seeing as they aren't just integers anymore, but I think the bonuses outweigh the added memory footprint. That being said, it should be relatively easy to swap between the two for projects if need be.