diff --git a/org/flixel/FlxSpriteGraphicLoader.as b/org/flixel/FlxSpriteGraphicLoader.as new file mode 100644 index 00000000..0847b04f --- /dev/null +++ b/org/flixel/FlxSpriteGraphicLoader.as @@ -0,0 +1,163 @@ +package org.flixel +{ + import flash.utils.ByteArray; + import flash.utils.Dictionary; + + /** + * The FlxSpriteGraphicLoader class allows graphics and animations + * to be loaded into a FlxSprite with their properties defined + * in an embedded XML asset. This enables sprite sheet and animation details to be + * kept outside of code and easily updated in a controlled fashion. + * An XML descriptor can be embedded into a variable + * or constant as follows: + *
+	 * [Embed(source="resource/example.xml", mimeType="application/octet-stream")]
+	 * private static const ExampleDescriptor : Class;
+ * + * An XML descriptor must adhear to the following schema: + *
+	 *<sprite>
+	 *	<animated>true</animated>
+	 *	<reverse>true</reverse>
+	 *	<unique>false</unique>
+	 *	<rotations>0</rotations>
+	 *	<frame>-1</frame>
+	 *	<antiAliasing>false</antiAliasing>
+	 *	<autoBuffer>false</autoBuffer>
+	 *	<cell width='30' height='11'/>
+	 *	<animations>
+	 *		<animation name='walk'>
+	 *			<framerate>30</framerate>
+	 * 			<looped>true</looped>
+	 * 			<frames from='0' to='18'/>
+	 * 		</animation>
+	 *	</animations>
+	 *</sprite>
+	 *
+ * + * Note that all tags in the descriptor are optional, but the attributes of included tags are not. + * You can add as many animation tags to the animations tag as you wish. You can also add as many + * frames tags to any animation tag as you wish. Once loaded, animations are idendified by their + * name attribute. + * Also note that if the rotations tag is not omitted and > 0 then FlxSprite.loadRotatedGraphic is called, + * otherwise FlxSprite.loadGraphic is called, and unnecessary parameters are ignored. + * Any combination of Graphic and Descriptor can be used. + * + * @see org.flixel.FlxSprite#loadGraphic() + * @see org.flixel.FlxSprite#loadRotatedGraphic() + * @see org.flixel.FlxSprite#addAnimation() + * + * @author Paul Moore + */ + public class FlxSpriteGraphicLoader + { + /** cached descriptors that don't need to be re-parsed */ + private static const cache:Dictionary = new Dictionary(true); + + /** + * Loads a graphic and animations into a sprite. + * + * @param FlxSprite the sprite to load the graphic and animations into + * @param Graphic the embedded graphic class to load + * @param Descriptor the embedded XML that describes the graphic + */ + public static function load (Sprite:FlxSprite, Graphic:Class, Descriptor:Class):void + { + var info:Info = cache[Descriptor] as Info; + if (info == null) + { + var bytes:ByteArray = new Descriptor() as ByteArray; + var data:String = bytes.readUTFBytes(bytes.length); + var xml:XML = new XML(data); + info = parseInfo(xml); + cache[Descriptor] = info; + } + if (info.rotations > 0) + Sprite.loadRotatedGraphic(Graphic, info.rotations, info.frame, info.antiAliasing, info.antiAliasing); + else + Sprite.loadGraphic(Graphic, info.animated, info.reverse, info.width, info.height, info.unique); + for each (var animation : Animation in info.animations) + Sprite.addAnimation(animation.name, animation.frames, animation.frameRate, animation.looped); + } + + /** + * Parses the XML descriptor. + * + * @param descriptor the XML to parse + * @return the sprite sheet info + */ + private static function parseInfo (descriptor : XML) : Info + { + var info : Info = new Info(descriptor.animated, descriptor.reverse, descriptor.cell.@width, descriptor.cell.@height, descriptor.unique, descriptor.rotations, descriptor.frame, descriptor.antiAliasing, descriptor.autoBuffer); + for each (var animation : XML in descriptor.animations.animation) + { + var frames : Array = new Array(); + for each (var frameRange : XML in animation.frames) + { + var from : uint = animation.frames.@from; + var to : uint = animation.frames.@to; + while (from <= to) + { + frames.push(from); + from++; + } + } + info.animations.push(new Animation(animation.@name, frames, animation.framerate, animation.looped)); + } + return info; + } + } +} + +/** + * A struct containing parameter information to be passed to the loadGraphic, loadRotatedGraphic, and addAnimation methods. + */ +class Info +{ + public var animated : Boolean; + public var reverse : Boolean; + public var width : uint; + public var height : uint; + public var unique : Boolean; + public var rotations : uint; + public var frame : int; + public var antiAliasing : Boolean; + public var autoBuffer : Boolean; + public var animations : Array; + + public function Info (animated:Boolean = false, reverse:Boolean = false, width:uint = 0, height:uint = 0, unique:Boolean = false, rotations:uint = 16, frame:int = -1, antiAliasing:Boolean = false, autoBuffer:Boolean = false, animations:Array = null) + { + this.animated = animated; + this.reverse = reverse; + this.width = width; + this.height = height; + this.unique = unique; + this.rotations = rotations, this.frame = frame; + this.antiAliasing = antiAliasing; + this.autoBuffer = autoBuffer; + + if (animations == null) + { + this.animations = new Array(); + } + } +} + +/** + * A struct containing the information required to build an animation. + */ +class Animation +{ + public var name : String; + public var frameRate : uint; + public var looped : Boolean; + public var frames : Array; + + public function Animation (name : String, frames : Array, frameRate : uint, looped : Boolean) + { + this.name = name; + this.frames = frames; + this.frameRate = frameRate; + this.looped = looped; + } +}