spine-runtimes/spine-as3/src/spine/SkeletonJson.as
2013-04-30 19:18:39 +02:00

250 lines
8.5 KiB
ActionScript

package spine {
import spine.animation.Animation;
import spine.animation.AttachmentTimeline;
import spine.animation.ColorTimeline;
import spine.animation.CurveTimeline;
import spine.animation.RotateTimeline;
import spine.animation.ScaleTimeline;
import spine.animation.Timeline;
import spine.animation.TranslateTimeline;
import spine.attachments.Attachment;
import spine.attachments.AttachmentLoader;
import spine.attachments.AttachmentType;
import spine.attachments.RegionAttachment;
public class SkeletonJson {
static public const TIMELINE_SCALE:String = "scale";
static public const TIMELINE_ROTATE:String = "rotate";
static public const TIMELINE_TRANSLATE:String = "translate";
static public const TIMELINE_ATTACHMENT:String = "attachment";
static public const TIMELINE_COLOR:String = "color";
public var attachmentLoader:AttachmentLoader;
public var scale:Number = 1;
public function SkeletonJson (attachmentLoader:AttachmentLoader = null) {
this.attachmentLoader = attachmentLoader;
}
public function readSkeletonData (json:String, name:String) : SkeletonData {
if (json == null)
throw new ArgumentError("json cannot be null.");
var skeletonData:SkeletonData = new SkeletonData();
skeletonData.name = name;
var root:Object = JSON.parse(json);
// Bones.
var boneData:BoneData;
for each (var boneMap:Object in root["bones"]) {
var parent:BoneData = null;
var parentName:String = boneMap["parent"];
if (parentName) {
parent = skeletonData.findBone(parentName);
if (!parent)
throw new Error("Parent bone not found: " + parentName);
}
boneData = new BoneData(boneMap["name"], parent);
boneData.length = (boneMap["length"] || 0) * scale;
boneData.x = (boneMap["x"] || 0) * scale;
boneData.y = (boneMap["y"] || 0) * scale;
boneData.rotation = (boneMap["rotation"] || 0);
boneData.scaleX = boneMap["scaleX"] || 1;
boneData.scaleY = boneMap["scaleY"] || 1;
skeletonData.addBone(boneData);
}
// Slots.
for each (var slotMap:Object in root["slots"]) {
var boneName:String = slotMap["bone"];
boneData = skeletonData.findBone(boneName);
if (!boneData)
throw new Error("Slot bone not found: " + boneName);
var slotData:SlotData = new SlotData(slotMap["name"], boneData);
var color:String = slotMap["color"];
if (color) {
slotData.r = toColor(color, 0);
slotData.g = toColor(color, 1);
slotData.b = toColor(color, 2);
slotData.a = toColor(color, 3);
}
slotData.attachmentName = slotMap["attachment"];
skeletonData.addSlot(slotData);
}
// Skins.
var skins:Object = root["skins"];
for (var skinName:String in skins) {
var skinMap:Object = skins[skinName];
var skin:Skin = new Skin(skinName);
for (var slotName:String in skinMap) {
var slotIndex:int = skeletonData.findSlotIndex(slotName);
var slotEntry:Object = skinMap[slotName];
for (var attachmentName:String in slotEntry) {
var attachment:Attachment = readAttachment(skin, attachmentName, slotEntry[attachmentName]);
if (attachment != null)
skin.addAttachment(slotIndex, attachmentName, attachment);
}
}
skeletonData.addSkin(skin);
if (skin.name == "default")
skeletonData.defaultSkin = skin;
}
// Animations.
var animations:Object = root["animations"];
for (var animationName:String in animations)
readAnimation(animationName, animations[animationName], skeletonData);
return skeletonData;
}
private function readAttachment (skin:Skin, name:String, map:Object) : Attachment {
name = map["name"] || name;
var type:AttachmentType = AttachmentType.valueOf(map["type"] || "region");
var attachment:Attachment = attachmentLoader.newAttachment(skin, type, name);
if (attachment is RegionAttachment) {
var regionAttachment:RegionAttachment = attachment as RegionAttachment;
regionAttachment.x = (map["x"] || 0) * scale;
regionAttachment.y = (map["y"] || 0) * scale;
regionAttachment.scaleX = map["scaleX"] || 1;
regionAttachment.scaleY = map["scaleY"] || 1;
regionAttachment.rotation = map["rotation"] || 0;
regionAttachment.width = (map["width"] || 32) * scale;
regionAttachment.height = (map["height"] || 32) * scale;
regionAttachment.updateOffset();
}
return attachment;
}
private function readAnimation (name:String, map:Object, skeletonData:SkeletonData) : void {
var timelines:Vector.<Timeline> = new Vector.<Timeline>();
var duration:Number = 0;
var bones:Object = map["bones"];
for (var boneName:String in bones) {
var boneIndex:int = skeletonData.findBoneIndex(boneName);
if (boneIndex == -1)
throw new Error("Bone not found: " + boneName);
var boneMap:Object = bones[boneName];
for (var timelineName:Object in boneMap) {
var timelineMap:Object = boneMap[timelineName];
if (timelineName == TIMELINE_ROTATE) {
var timeline:RotateTimeline = new RotateTimeline(count(timelineMap));
timeline.boneIndex = boneIndex;
var frameIndex:int = 0;
for each (var valueMap:Object in timelineMap) {
timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]);
readCurve(timeline, frameIndex, valueMap);
frameIndex++;
}
timelines.push(timeline);
duration = Math.max(duration, timeline.frames[timeline.frameCount * 2 - 2]);
} else if (timelineName == TIMELINE_TRANSLATE || timelineName == TIMELINE_SCALE) {
var timeline1:TranslateTimeline;
var timelineScale:Number = 1;
if (timelineName == TIMELINE_SCALE)
timeline1 = new ScaleTimeline(count(timelineMap));
else {
timeline1 = new TranslateTimeline(count(timelineMap));
timelineScale = scale;
}
timeline1.boneIndex = boneIndex;
var frameIndex1:int = 0;
for each (var valueMap1:Object in timelineMap) {
var x:Number = (valueMap1["x"] || 0) * timelineScale;
var y:Number = (valueMap1["y"] || 0) * timelineScale;
timeline1.setFrame(frameIndex1, valueMap1["time"], x, y);
readCurve(timeline1, frameIndex1, valueMap1);
frameIndex1++;
}
timelines.push(timeline1);
duration = Math.max(duration, timeline1.frames[timeline1.frameCount * 3 - 3]);
} else
throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
}
}
var slots:Object = map["slots"];
for (var slotName:String in slots) {
var slotMap:Object = slots[slotName];
var slotIndex:int = skeletonData.findSlotIndex(slotName);
for (var timelineName2:Object in boneMap) {
var timelineMap2:Object = boneMap[timelineName2];
if (timelineName2 == TIMELINE_COLOR) {
var timeline2:ColorTimeline = new ColorTimeline(count(timelineMap2));
timeline2.slotIndex = slotIndex;
var frameIndex2:int = 0;
for each (var valueMap2:Object in timelineMap2) {
var color:String = valueMap["color"];
var r:Number = toColor(color, 0);
var g:Number = toColor(color, 1);
var b:Number = toColor(color, 2);
var a:Number = toColor(color, 3);
timeline2.setFrame(frameIndex2, valueMap2["time"], r, g, b, a);
readCurve(timeline2, frameIndex2, valueMap);
frameIndex2++;
}
timelines.push(timeline2);
duration = Math.max(duration, timeline2.frames[timeline2.frameCount * 5 - 5]);
} else if (timelineName2 == TIMELINE_ATTACHMENT) {
var timeline3:AttachmentTimeline = new AttachmentTimeline(count(timelineMap2));
timeline3.slotIndex = slotIndex;
var frameIndex3:int = 0;
for each (var valueMap3:Object in timelineMap2) {
timeline3.setFrame(frameIndex3++, valueMap3["time"], valueMap3["name"]);
}
timelines.push(timeline);
duration = Math.max(duration, timeline3.frames[timeline3.frameCount - 1]);
} else
throw new Error("Invalid timeline type for a slot: " + timelineName2 + " (" + slotName + ")");
}
}
skeletonData.addAnimation(new Animation(name, timelines, duration));
}
private function readCurve (timeline:CurveTimeline, frameIndex:int, valueMap:Object) : void {
var curve:Object = valueMap["curve"];
if (curve == null)
return;
if (curve == "stepped")
timeline.setStepped(frameIndex);
else if (curve is Array) {
timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]);
}
}
static private function toColor (hexString:String, colorIndex:int) : Number {
if (hexString.length != 8)
throw new ArgumentError("Color hexidecimal length must be 8, recieved: " + hexString);
return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255;
}
static private function count (map:Object) : int {
var count:int = 0;
for (var key:String in map)
count++;
return count;
}
}
}