├── .actionScriptProperties ├── .flexProperties ├── .gitignore ├── .project ├── .settings └── org.eclipse.core.resources.prefs ├── Animator.exe ├── README.md ├── guide_make_transition.gif ├── libs └── ui.swc └── src ├── Animator-app.xml ├── Animator.mxml ├── assets ├── +.png ├── -.png ├── icon128.png ├── icon16.png ├── icon32.png └── icon48.png └── com └── wonder ├── AnimState.as ├── AnimTransition.as ├── Condition.as ├── DataParser.as ├── DragSprite.as ├── EditController.as └── Parameter.as /.actionScriptProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /.flexProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin-debug/Animator-app.xml 2 | bin-debug/Animator.swf 3 | /bin-debug 4 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Animator 4 | 5 | 6 | 7 | 8 | 9 | com.adobe.flexbuilder.project.flexbuilder 10 | 11 | 12 | 13 | 14 | com.adobe.flexbuilder.project.apollobuilder 15 | 16 | 17 | 18 | 19 | 20 | com.adobe.flexbuilder.project.apollonature 21 | com.adobe.flexbuilder.project.flexnature 22 | com.adobe.flexbuilder.project.actionscriptnature 23 | 24 | 25 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Sat Mar 28 18:13:06 CST 2015 2 | eclipse.preferences.version=1 3 | encoding/=utf-8 4 | -------------------------------------------------------------------------------- /Animator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/Animator.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Animator 2 | A Visual FSM Editor like Unity Mecanim System 3 | 4 | Project 5 | ======= 6 | * A Flex project 7 | * IDE: FlashBuilder 8 | * can be published as desktop application for Windows and Mac OS 9 | 10 | Feature 11 | ======= 12 | * export *.json file 13 | * support dragonBones skeleton file for Egret Engine(http://www.egret-labs.org/dragonbones) 14 | 15 | Guide 16 | ===== 17 | ![image](https://github.com/wonderyue/Animator/blob/master/guide_make_transition.gif) 18 | 19 | 工程 20 | ==== 21 | * Flex工程 22 | * IDE: FlashBuilder 23 | * 可以发布为桌面应用程序(支持Windows和Mac) 24 | 25 | 功能 26 | ==== 27 | * 将编辑过的状态机导出为json文件供程序解析 28 | * 支持dragonBones导出的Egret白鹭引擎格式skeleton.json文件,点击open打开或直接拖拽到视窗内(支持多文件) 29 | * 主要操作方式可搜索参考Unity的Mecanim,不再赘述(=。。=) 30 | -------------------------------------------------------------------------------- /guide_make_transition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/guide_make_transition.gif -------------------------------------------------------------------------------- /libs/ui.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/libs/ui.swc -------------------------------------------------------------------------------- /src/Animator-app.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 18 | Animator 19 | 20 | 21 | Animator 22 | 23 | 25 | Animator 26 | 27 | 30 | 1.0.0 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | [此值将由 Flash Builder 在输出 app.xml 中覆盖] 50 | 51 | 52 | AnimatorEditor 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 960 74 | 75 | 76 | 480 77 | 78 | 79 | 0 80 | 81 | 82 | 0 83 | 84 | 85 | 960 480 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | false 109 | false 110 | false 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 128 | 129 | assets/icon16.png 130 | assets/icon32.png 131 | 132 | assets/icon48.png 133 | 135 | assets/icon128.png 136 | 137 | 138 | 141 | 142 | 143 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 192 | 193 | 194 | 195 | 196 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /src/Animator.mxml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 12 | 14 | 15 | 17 | 18 | 19 | 20 | 23 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | 45 | 47 | 48 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 65 | 66 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /src/assets/+.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/+.png -------------------------------------------------------------------------------- /src/assets/-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/-.png -------------------------------------------------------------------------------- /src/assets/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/icon128.png -------------------------------------------------------------------------------- /src/assets/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/icon16.png -------------------------------------------------------------------------------- /src/assets/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/icon32.png -------------------------------------------------------------------------------- /src/assets/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderyue/Animator/33e55bbe742d9c0d7151c590ff91b8503dceead3/src/assets/icon48.png -------------------------------------------------------------------------------- /src/com/wonder/AnimState.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | import flash.display.SimpleButton; 4 | import flash.display.Sprite; 5 | import flash.events.ContextMenuEvent; 6 | import flash.events.MouseEvent; 7 | import flash.filters.DropShadowFilter; 8 | import flash.filters.GlowFilter; 9 | import flash.text.TextField; 10 | import flash.text.TextFormat; 11 | import flash.ui.ContextMenu; 12 | import flash.ui.ContextMenuItem; 13 | 14 | import flashx.textLayout.formats.TextAlign; 15 | 16 | public class AnimState extends DragSprite 17 | { 18 | public static var ANYSTATE_ID:String = "anyState"; 19 | private static var DEFAULT_COLOR:int = 0xFFD700; 20 | private static var NORMAL_COLOR:int = 0xD3D3D3; 21 | private static var ANYSTATE_COLOR:int = 0x66CDAA; 22 | private var m_isDefaultState:Boolean = false; 23 | private var m_isSelected:Boolean = false; 24 | 25 | private var m_textField:TextField; 26 | private var m_bg:Sprite; 27 | private var m_btn:SimpleButton; 28 | private var m_id:String; 29 | private var m_animation:String; 30 | 31 | public function AnimState(id:String) 32 | { 33 | super(); 34 | m_animation = m_id = id; 35 | initSkin(); 36 | initMenu(); 37 | } 38 | 39 | public function set id(value:String):void 40 | { 41 | m_id = value; 42 | m_textField.text = m_id; 43 | } 44 | 45 | public function get id():String{ 46 | return m_id; 47 | } 48 | 49 | public function get animation():String 50 | { 51 | return m_animation; 52 | } 53 | 54 | public function set animation(value:String):void 55 | { 56 | m_animation = value; 57 | } 58 | 59 | public function get isDefaultState():Boolean 60 | { 61 | return m_isDefaultState; 62 | } 63 | 64 | public function set isDefaultState(value:Boolean):void 65 | { 66 | if(m_isDefaultState == value) { 67 | return; 68 | } 69 | if (value) { 70 | m_bg.graphics.clear(); 71 | m_bg.graphics.beginFill(DEFAULT_COLOR); 72 | m_bg.graphics.drawRoundRect(0,0,150,40,18,18); 73 | m_bg.graphics.endFill(); 74 | } else { 75 | m_bg.graphics.clear(); 76 | m_bg.graphics.beginFill(NORMAL_COLOR); 77 | m_bg.graphics.drawRoundRect(0,0,150,40,18,18); 78 | m_bg.graphics.endFill(); 79 | } 80 | m_isDefaultState = value; 81 | } 82 | 83 | public function get isAnyState():Boolean 84 | { 85 | return id == ANYSTATE_ID; 86 | } 87 | 88 | private function initSkin():void{ 89 | m_bg = new Sprite(); 90 | m_bg.graphics.clear(); 91 | m_bg.graphics.beginFill(isAnyState?ANYSTATE_COLOR:NORMAL_COLOR); 92 | m_bg.graphics.drawRoundRect(0,0,150,40,18,18); 93 | m_bg.graphics.endFill(); 94 | addChild(m_bg); 95 | m_bg.filters = [new DropShadowFilter(2,90,0,0.8)]; 96 | 97 | m_textField = new TextField(); 98 | m_textField.selectable = false; 99 | var textFormat:TextFormat = new TextFormat(); 100 | textFormat.font = "Arial"; 101 | textFormat.size = 20; 102 | m_textField.textColor = 0x000000; 103 | textFormat.align = TextAlign.CENTER; 104 | m_textField.defaultTextFormat = textFormat; 105 | m_textField.text = m_id; 106 | m_textField.width = m_bg.width; 107 | m_textField.height = m_bg.height; 108 | addChild(m_textField); 109 | } 110 | 111 | private function initMenu():void 112 | { 113 | var contextMenu:ContextMenu = new ContextMenu(); 114 | var contextItem1:ContextMenuItem = new ContextMenuItem("Make Transition"); 115 | var contextItem2:ContextMenuItem = new ContextMenuItem("Set As Default"); 116 | var contextItem3:ContextMenuItem = new ContextMenuItem("Copy"); 117 | var contextItem4:ContextMenuItem = new ContextMenuItem("Delete"); 118 | var self:AnimState = this; 119 | contextItem1.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void{ 120 | EditController.getInstance().makeTransition(self); 121 | }); 122 | contextItem2.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void{ 123 | EditController.getInstance().setDefaultState(self); 124 | }); 125 | contextItem3.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void{ 126 | var state:AnimState = EditController.getInstance().addState(self.id + "(copy)", x + 30, y + 30); 127 | state.animation = self.animation; 128 | }); 129 | contextItem4.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void{ 130 | EditController.getInstance().removeState(self); 131 | }); 132 | contextMenu.customItems.push(contextItem1); 133 | if (!isAnyState) 134 | { 135 | contextMenu.customItems.push(contextItem2); 136 | contextMenu.customItems.push(contextItem3); 137 | contextMenu.customItems.push(contextItem4); 138 | } 139 | contextMenu.hideBuiltInItems(); 140 | this.contextMenu = contextMenu; 141 | } 142 | 143 | public function get isSelected():Boolean 144 | { 145 | return m_isSelected; 146 | } 147 | 148 | public function set isSelected(bool:Boolean):void 149 | { 150 | if (bool) 151 | { 152 | var filter:Array = [new GlowFilter(0x000ff0, 1.0, 2.0, 2.0, 20, 1, true, false)]; 153 | this.filters = filter; 154 | } else { 155 | this.filters = null; 156 | } 157 | m_isSelected = bool; 158 | } 159 | 160 | override protected function onIn(e:MouseEvent):void 161 | { 162 | if (!EditController.getInstance().hasDragState()) 163 | { 164 | super.onIn(e); 165 | } 166 | } 167 | 168 | override protected function onMove(e:MouseEvent):void 169 | { 170 | super.onMove(e); 171 | EditController.getInstance().updateArrow(this); 172 | } 173 | 174 | override protected function onMouseUp(e:MouseEvent):void 175 | { 176 | super.onMouseUp(e); 177 | EditController.getInstance().updateArrow(this); 178 | EditController.getInstance().curState = this; 179 | } 180 | 181 | public function destroy():void 182 | { 183 | if (parent) 184 | { 185 | parent.removeChild(this); 186 | } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /src/com/wonder/AnimTransition.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.ContextMenuEvent; 5 | import flash.events.Event; 6 | import flash.events.MouseEvent; 7 | import flash.filters.GlowFilter; 8 | import flash.geom.Point; 9 | import flash.ui.ContextMenu; 10 | import flash.ui.ContextMenuItem; 11 | 12 | public class AnimTransition 13 | { 14 | private var m_from:AnimState; 15 | private var m_to:AnimState; 16 | private var m_arrow:Sprite; 17 | private var m_isSelected:Boolean = false; 18 | private var m_conditionArray:Array; 19 | 20 | public function AnimTransition(from:AnimState) 21 | { 22 | super(); 23 | m_from = from; 24 | m_arrow = new Sprite(); 25 | EditController.getInstance().arrowContainer.addChild(m_arrow); 26 | m_arrow.addEventListener(MouseEvent.CLICK,onMouseClick); 27 | m_arrow.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 28 | m_arrow.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 29 | m_arrow.addEventListener(Event.REMOVED_FROM_STAGE,onDestroy); 30 | m_conditionArray = new Array(); 31 | initMenu(); 32 | } 33 | 34 | private function initMenu():void 35 | { 36 | var contextMenu:ContextMenu = new ContextMenu(); 37 | var contextItem1:ContextMenuItem = new ContextMenuItem("Delete"); 38 | var self:AnimTransition = this; 39 | contextItem1.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void{ 40 | EditController.getInstance().removeTransition(self); 41 | EditController.getInstance().curArrow = null; 42 | }); 43 | contextMenu.customItems.push(contextItem1); 44 | contextMenu.hideBuiltInItems(); 45 | m_arrow.contextMenu = contextMenu; 46 | } 47 | 48 | public function get conditionArray():Array 49 | { 50 | return m_conditionArray; 51 | } 52 | 53 | public function addCondition():Condition 54 | { 55 | var condition:Condition = new Condition(new Parameter(Parameter.COMPLETE_ID, Parameter.TYPE_COMPLETE)); 56 | m_conditionArray.push(condition); 57 | return condition; 58 | } 59 | 60 | public function removeCondition(condition:Condition):void 61 | { 62 | for (var i:int = 0; i < m_conditionArray.length; i++) 63 | { 64 | var element:Condition = m_conditionArray[i] as Condition; 65 | if (element == condition) 66 | { 67 | m_conditionArray.splice(i,1); 68 | return; 69 | } 70 | } 71 | } 72 | 73 | public function get from():AnimState 74 | { 75 | return m_from; 76 | } 77 | 78 | public function get to():AnimState 79 | { 80 | return m_to; 81 | } 82 | 83 | public function set to(value:AnimState):void 84 | { 85 | m_arrow.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 86 | m_to = value; 87 | } 88 | 89 | private function onDestroy(e:Event):void 90 | { 91 | m_arrow.removeEventListener(MouseEvent.CLICK,onMouseClick); 92 | m_arrow.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 93 | m_arrow.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); 94 | } 95 | 96 | public function destroy():void 97 | { 98 | if (m_arrow.parent) 99 | { 100 | m_arrow.parent.removeChild(m_arrow); 101 | } 102 | } 103 | 104 | public function get isSelected():Boolean 105 | { 106 | return m_isSelected; 107 | } 108 | 109 | public function set isSelected(bool:Boolean):void 110 | { 111 | if (bool) 112 | { 113 | var filter:Array = [new GlowFilter(0xff0000, 1.0, 2.0, 2.0, 20, 1, true, false)]; 114 | m_arrow.filters = filter; 115 | } else { 116 | m_arrow.filters = null; 117 | } 118 | m_isSelected = bool; 119 | } 120 | 121 | public function draw():void 122 | { 123 | var fromCenter:Point = new Point(m_from.x + m_from.width / 2, m_from.y + m_from.height / 2); 124 | var toCenter:Point; 125 | if(m_to){ 126 | toCenter = new Point(m_to.x + m_to.width / 2, m_to.y + m_to.height / 2); 127 | }else{ 128 | toCenter = new Point(m_arrow.stage.mouseX, m_arrow.stage.mouseY); 129 | toCenter = m_arrow.parent.globalToLocal(toCenter); 130 | } 131 | m_arrow.graphics.clear(); 132 | m_arrow.graphics.lineStyle(3,0x000000,0.7); 133 | var len:int = 10;//箭头长度 134 | var _a:int = 8;//箭头与直线的夹角 135 | var angle:int = Math.atan2((fromCenter.y-toCenter.y), (fromCenter.x-toCenter.x))*(180/Math.PI); 136 | //防止双向Transition重合,重新确定端点 137 | var begin:Point = fromCenter; 138 | var end:Point = toCenter; 139 | if(m_to){ 140 | begin = new Point(fromCenter.x + 5*Math.cos((angle+90)*(Math.PI/180)), fromCenter.y + 5*Math.sin((angle+90)*(Math.PI/180))); 141 | end = new Point(toCenter.x + 5*Math.cos((angle+90)*(Math.PI/180)), toCenter.y + 5*Math.sin((angle+90)*(Math.PI/180))); 142 | } 143 | var arrowPt:Point = new Point((begin.x+end.x)/2, (begin.y+end.y)/2); 144 | m_arrow.graphics.moveTo(arrowPt.x, arrowPt.y); 145 | m_arrow.graphics.lineTo(arrowPt.x+len*Math.cos((angle-_a)*(Math.PI/180)), arrowPt.y+len*Math.sin((angle-_a)*(Math.PI/180))); 146 | m_arrow.graphics.moveTo(arrowPt.x, arrowPt.y); 147 | m_arrow.graphics.lineTo(arrowPt.x+len*Math.cos((angle+_a)*(Math.PI/180)), arrowPt.y+len*Math.sin((angle+_a)*(Math.PI/180))); 148 | m_arrow.graphics.moveTo(begin.x,begin.y); 149 | m_arrow.graphics.lineTo(end.x,end.y); 150 | } 151 | 152 | private function onMouseMove(e:MouseEvent):void 153 | { 154 | draw(); 155 | } 156 | 157 | private function onMouseUp(e:MouseEvent):void 158 | { 159 | var state:AnimState = EditController.getInstance().getStateByMouse(new Point(m_arrow.stage.mouseX, m_arrow.stage.mouseY)); 160 | if(state && !to && !state.isAnyState){ 161 | to = state; 162 | draw(); 163 | EditController.getInstance().checkTransitionExist(this); 164 | } 165 | } 166 | 167 | private function onMouseClick(e:MouseEvent):void 168 | { 169 | if(m_to){ 170 | EditController.getInstance().curArrow = this; 171 | } 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /src/com/wonder/Condition.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | public class Condition 4 | { 5 | private var m_parameter:Parameter; 6 | private var m_value:int = 0; 7 | private var m_logic:int = 0; 8 | 9 | public static var LOGIC_EQUAL:int = 0; 10 | public static var LOGIC_GREATER:int = 1; 11 | public static var LOGIC_LESS:int = 2; 12 | public static var LOGIC_NOTEQUAL:int = 3; 13 | 14 | public function Condition(param:Parameter) 15 | { 16 | parameter = param; 17 | } 18 | 19 | public function get parameter():Parameter 20 | { 21 | return m_parameter; 22 | } 23 | 24 | public function set parameter(value:Parameter):void 25 | { 26 | m_parameter = value; 27 | } 28 | 29 | public function get id():String 30 | { 31 | return m_parameter.id; 32 | } 33 | 34 | public function set id(value:String):void 35 | { 36 | m_parameter.id = value; 37 | } 38 | 39 | public function get type():int 40 | { 41 | return m_parameter.type; 42 | } 43 | 44 | public function set type(value:int):void 45 | { 46 | m_parameter.type = value; 47 | } 48 | 49 | public function get value():int 50 | { 51 | return m_value; 52 | } 53 | 54 | public function set value(value:int):void 55 | { 56 | m_value = value; 57 | } 58 | 59 | public function get logic():int 60 | { 61 | return m_logic; 62 | } 63 | 64 | public function set logic(value:int):void 65 | { 66 | m_logic = value; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/com/wonder/DataParser.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | import flash.events.Event; 4 | import flash.events.FileListEvent; 5 | import flash.filesystem.File; 6 | import flash.filesystem.FileMode; 7 | import flash.filesystem.FileStream; 8 | import flash.net.FileFilter; 9 | 10 | public class DataParser 11 | { 12 | private static var FILETYPE_SKELETON:int = 1; 13 | private static var FILETYPE_FSM:int = 2; 14 | 15 | private static function generateJson(stateArr:Array,transitionArr:Array,paramArr:Array,armatureInfo:Object):String 16 | { 17 | var output:String = ""; 18 | var stateJsonArr:Array = new Array(); 19 | for each (var state:AnimState in stateArr) 20 | { 21 | var stateObj:Object = new Object(); 22 | stateObj["state"] = state.id; 23 | stateObj["animation"] = state.animation; 24 | stateObj["transition"] = new Array(); 25 | stateObj["x"] = state.x; 26 | stateObj["y"] = state.y; 27 | if (state.isDefaultState) 28 | { 29 | stateObj.default = true; 30 | } 31 | for each (var transition:AnimTransition in transitionArr) 32 | { 33 | if (transition.from == state) 34 | { 35 | var transitionObj:Object = new Object(); 36 | transitionObj["nextState"] = transition.to.id; 37 | transitionObj.condition = new Array(); 38 | for each (var condition:Condition in transition.conditionArray) 39 | { 40 | if (condition.type == Parameter.TYPE_COMPLETE) 41 | { 42 | condition.id = Parameter.COMPLETE_ID; 43 | } 44 | if (condition.id) 45 | { 46 | var conditionObj:Object = new Object(); 47 | conditionObj["id"] = condition.id; 48 | conditionObj["type"] = condition.type; 49 | conditionObj["logic"] = condition.logic; 50 | conditionObj["value"] = condition.value; 51 | transitionObj.condition.push(conditionObj); 52 | } 53 | } 54 | stateObj.transition.push(transitionObj); 55 | } 56 | } 57 | stateJsonArr.push(stateObj); 58 | } 59 | var paramJsonArr:Array = new Array(); 60 | for each (var param:Parameter in paramArr) 61 | { 62 | paramJsonArr.push({"id":param.id, "type":param.type}); 63 | } 64 | return JSON.stringify({"state":stateJsonArr, "parameter":paramArr, "armatureInfo":armatureInfo}); 65 | } 66 | 67 | private static function saveFile(fileName:String, content:String):void 68 | { 69 | var fileToSave:File = File.documentsDirectory; 70 | fileToSave = fileToSave.resolvePath(fileName); 71 | fileToSave.browseForSave("Select Directory"); 72 | fileToSave.addEventListener(Event.SELECT, directorySelected); 73 | 74 | function directorySelected(event:Event):void 75 | { 76 | var file:File = event.target as File; 77 | var fileStream:FileStream = new FileStream(); 78 | fileStream.open(file, FileMode.WRITE); 79 | fileStream.writeUTFBytes(content); 80 | } 81 | } 82 | 83 | public static function browseForOpenFile():void 84 | { 85 | var fileToSave:File = File.documentsDirectory; 86 | fileToSave.browseForOpenMultiple("Select Directory",[new FileFilter("Text", "*.json")]); 87 | fileToSave.addEventListener(FileListEvent.SELECT_MULTIPLE, onFileSelect); 88 | function onFileSelect(event:FileListEvent):void 89 | { 90 | parseFiles(event.files); 91 | } 92 | } 93 | 94 | public static function parseFiles(files:Array):void 95 | { 96 | if(files.length == 1){ 97 | parseSingleFile(files[0]); 98 | }else{ 99 | for (var i:int = 0; i < files.length; i++) 100 | { 101 | var file:File = files[i]; 102 | parseSingleFile(file); 103 | } 104 | } 105 | } 106 | 107 | private static function parseSingleFile(file:File):void 108 | { 109 | var fs:FileStream = new FileStream(); 110 | fs.open(File(file),FileMode.READ); 111 | var content:String = fs.readUTFBytes(fs.bytesAvailable); 112 | fs.close(); 113 | 114 | var type:int; 115 | if (file.name.indexOf("fsm.json") != -1) 116 | { 117 | type = FILETYPE_FSM; 118 | } 119 | else if (file.name.indexOf("skeleton.json") != -1) 120 | { 121 | type = FILETYPE_SKELETON; 122 | } 123 | 124 | switch(type) 125 | { 126 | case FILETYPE_SKELETON: 127 | { 128 | var obj:Object = JSON.parse(content); 129 | var stateStrArr:Array = new Array(); 130 | var animationArr:Array = new Array(); 131 | for each (var ani:Object in obj["armature"][0]["animation"]) 132 | { 133 | stateStrArr.push({"state":ani["name"],"animation":ani["name"]}); 134 | if (animationArr.indexOf(ani["name"]) == -1) 135 | { 136 | animationArr.push(ani["name"]); 137 | } 138 | } 139 | EditController.getInstance().addStates(stateStrArr); 140 | EditController.getInstance().armatureInfo[obj["armature"][0]["name"]] = animationArr; 141 | break; 142 | } 143 | case FILETYPE_FSM: 144 | { 145 | var contentObj:Object = JSON.parse(content); 146 | var stateArr:Array = contentObj["state"]; 147 | var paramArr:Array = contentObj["parameter"]; 148 | var armatureInfo:Object = contentObj["armatureInfo"]; 149 | var stateStrArray:Array = new Array(); 150 | for each (var oneStateObj:Object in stateArr) 151 | { 152 | if (oneStateObj["state"] != AnimState.ANYSTATE_ID) 153 | { 154 | stateStrArray.push({"state":oneStateObj["state"],"animation":oneStateObj["animation"],"default":oneStateObj["default"]}); 155 | } 156 | } 157 | EditController.getInstance().initStates(stateStrArray,file.name.split(".")[0]); 158 | for each (var state:AnimState in EditController.getInstance().stateArray) 159 | { 160 | for each (var stateObj:Object in stateArr) 161 | { 162 | if (stateObj["state"] == state.id) 163 | { 164 | state.x = stateObj["x"]; 165 | state.y = stateObj["y"]; 166 | for each (var transitionObj:Object in stateObj["transition"]) 167 | { 168 | var transition:AnimTransition = EditController.getInstance().makeTransition(state,false); 169 | transition.to = EditController.getInstance().getStateById(transitionObj["nextState"]); 170 | for each (var conditionObj:Object in transitionObj.condition) 171 | { 172 | var condition:Condition = transition.addCondition(); 173 | condition.id = conditionObj["id"]; 174 | condition.type = conditionObj["type"]; 175 | condition.logic = conditionObj["logic"]; 176 | condition.value = conditionObj["value"]; 177 | } 178 | } 179 | } 180 | EditController.getInstance().updateArrow(state); 181 | } 182 | } 183 | for each (var oneParamObj:Object in paramArr) 184 | { 185 | EditController.getInstance().addParam(new Parameter(oneParamObj["id"], oneParamObj["type"])); 186 | } 187 | EditController.getInstance().armatureInfo = armatureInfo; 188 | break; 189 | } 190 | default: 191 | { 192 | break; 193 | } 194 | } 195 | } 196 | 197 | public static function saveFsmJson(fileName:String,stateArr:Array,transitionArr:Array,paramArr:Array,armatureInfo:Object):void 198 | { 199 | saveFile(fileName+(fileName.indexOf("fsm") == -1?"_fsm.json":".json"),generateJson(stateArr,transitionArr,paramArr,armatureInfo)); 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /src/com/wonder/DragSprite.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | import flash.display.Sprite; 4 | import flash.display.StageQuality; 5 | import flash.events.Event; 6 | import flash.events.MouseEvent; 7 | import flash.geom.Rectangle; 8 | 9 | public class DragSprite extends Sprite 10 | { 11 | private var m_isDrag:Boolean; 12 | private var m_border:int = 5; 13 | public function DragSprite() 14 | { 15 | addEventListener(Event.ADDED_TO_STAGE,onAdd); 16 | addEventListener(Event.REMOVED_FROM_STAGE,onRemoveEvent); 17 | } 18 | 19 | public function get isDrag():Boolean 20 | { 21 | return m_isDrag; 22 | } 23 | 24 | protected function onAdd(event:Event):void 25 | { 26 | removeEventListener(Event.ADDED_TO_STAGE,onAdd); 27 | addEventListener(MouseEvent.MOUSE_OVER,onIn); 28 | } 29 | 30 | protected function onRemoveEvent(e:Event=null):void 31 | { 32 | removeEventListener(MouseEvent.MOUSE_OVER,onIn); 33 | onOut(); 34 | } 35 | 36 | protected function onIn(event:MouseEvent):void 37 | { 38 | addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); 39 | addEventListener(MouseEvent.MOUSE_UP,onMouseUp); 40 | addEventListener(MouseEvent.MOUSE_MOVE,onMove); 41 | addEventListener(MouseEvent.MOUSE_OUT,onOut); 42 | addEventListener(MouseEvent.RIGHT_MOUSE_DOWN,onOut); 43 | } 44 | 45 | protected function onRelease(event:MouseEvent = null):void 46 | { 47 | m_isDrag = false; 48 | } 49 | 50 | protected function onOut(event:MouseEvent = null):void 51 | { 52 | m_isDrag = false; 53 | removeEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); 54 | removeEventListener(MouseEvent.MOUSE_UP,onMouseUp); 55 | removeEventListener(MouseEvent.MOUSE_MOVE,onMove); 56 | removeEventListener(MouseEvent.MOUSE_OUT,onOut); 57 | removeEventListener(MouseEvent.RIGHT_MOUSE_DOWN,onOut); 58 | removeEventListener(Event.REMOVED_FROM_STAGE,onRemoveEvent); 59 | } 60 | 61 | protected function onMove(e:MouseEvent):void 62 | { 63 | if(m_isDrag){ 64 | this.startDrag(false); 65 | if(stage)stage.quality = StageQuality.LOW; 66 | } 67 | e.stopImmediatePropagation(); 68 | } 69 | 70 | protected function onMouseUp(e:MouseEvent):void 71 | { 72 | m_isDrag = false; 73 | this.stopDrag(); 74 | x = int(x); 75 | y = int(y); 76 | if(stage)stage.quality = StageQuality.BEST; 77 | } 78 | 79 | protected function onMouseDown(e:MouseEvent):void 80 | { 81 | m_isDrag = true; 82 | e.stopImmediatePropagation(); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/com/wonder/EditController.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.MouseEvent; 5 | import flash.geom.Point; 6 | import flash.geom.Rectangle; 7 | 8 | import mx.collections.ArrayCollection; 9 | import mx.controls.Alert; 10 | 11 | import spark.components.Button; 12 | import spark.components.DropDownList; 13 | import spark.components.HGroup; 14 | import spark.components.Image; 15 | import spark.components.Panel; 16 | import spark.components.Scroller; 17 | import spark.components.TextInput; 18 | import spark.components.VGroup; 19 | import spark.components.supportClasses.SkinnableComponent; 20 | import spark.events.IndexChangeEvent; 21 | import spark.events.TextOperationEvent; 22 | import spark.layouts.VerticalAlign; 23 | 24 | public class EditController 25 | { 26 | private static var _instance:EditController; 27 | private var m_editLayer:Sprite; 28 | private var m_inspector:VGroup; 29 | private var m_stateInputer:TextInput; 30 | private var m_animationInputer:TextInput; 31 | private var m_stateArray:Array; 32 | private var m_transitionArray:Array; 33 | private var m_paramArray:Array; 34 | private var m_defaultState:AnimState = null; 35 | private var m_arrowContainer:Sprite; 36 | private var m_curArrow:AnimTransition = null; 37 | private var m_skeletonName:String; 38 | private var m_curState:AnimState = null; 39 | private var INPUT_ID:String = "input"; 40 | private var LOGIC_ID:String = "logic"; 41 | private var VALUE_ID:String = "value"; 42 | private var REMOVE_ID:String = "remove"; 43 | private var m_paramList:VGroup; 44 | private var m_paramScroller:Scroller; 45 | private var m_paramPanel:Panel; 46 | private var m_armatureInfo:Object; 47 | 48 | public static function getInstance():EditController 49 | { 50 | return _instance; 51 | } 52 | 53 | public function EditController(main:Animator) 54 | { 55 | m_editLayer = main.editLayer; 56 | m_inspector = main.transitionInspector; 57 | m_stateInputer = main.stateIdInputer; 58 | m_animationInputer = main.animationInputer; 59 | m_paramList = main.paramList; 60 | m_paramScroller = main.paramScroller; 61 | m_paramPanel = main.paramPanel; 62 | _instance = this; 63 | initStates(); 64 | m_stateInputer.addEventListener(TextOperationEvent.CHANGE,function(e:TextOperationEvent):void{ 65 | m_curState.id = e.target.text; 66 | }) 67 | m_animationInputer.addEventListener(TextOperationEvent.CHANGE,function(e:TextOperationEvent):void{ 68 | m_curState.animation = e.target.text; 69 | }) 70 | } 71 | 72 | private function checkStateIdExist(id:String):Boolean 73 | { 74 | for (var i:int = 0; i < m_stateArray.length; i++) 75 | { 76 | var element:AnimState = m_stateArray[i] as AnimState; 77 | if (id == element.id) 78 | { 79 | Alert.show("State Already Exists!"); 80 | return true; 81 | } 82 | } 83 | return false; 84 | } 85 | 86 | private function generateNewStateId(id:String):String 87 | { 88 | if (id.indexOf("Untitled") == -1) 89 | { 90 | return checkStateIdExist(id)?id+"(new)":id; 91 | } 92 | var max:int = -1; 93 | for (var i:int = 0; i < m_stateArray.length; i++) 94 | { 95 | var element:AnimState = m_stateArray[i] as AnimState; 96 | if (element.id.indexOf("Untitled") != -1) 97 | { 98 | var arr:Array = element.id.split("Untitled"); 99 | if (arr.length > 1) 100 | { 101 | max = Math.max(max, parseInt(arr[1])); 102 | } 103 | } 104 | } 105 | return "Untitled"+(max+1); 106 | } 107 | 108 | public function addState(id:String = "Untitled", x:Number = 0, y:Number = 0):AnimState 109 | { 110 | var state:AnimState = new AnimState(generateNewStateId(id)); 111 | state.x = x; 112 | state.y = y; 113 | m_editLayer.addChild(state); 114 | m_stateArray.push(state); 115 | return state; 116 | } 117 | 118 | public function removeState(state:AnimState):void 119 | { 120 | for (var i:int = 0; i < m_stateArray.length; i++) 121 | { 122 | var oneState:AnimState = m_stateArray[i]; 123 | if(oneState == state){ 124 | for (var j:int = 0; j < m_transitionArray.length; j++) 125 | { 126 | var oneTransition:AnimTransition = m_transitionArray[j]; 127 | if(oneTransition.to == state || oneTransition.from == state){ 128 | m_transitionArray.splice(j,1); 129 | oneTransition.destroy(); 130 | j--; 131 | } 132 | } 133 | m_stateArray.splice(i,1); 134 | state.destroy(); 135 | return; 136 | } 137 | } 138 | } 139 | 140 | public function reset():void 141 | { 142 | m_editLayer.removeChildren(); 143 | m_inspector.removeAllElements(); 144 | m_paramList.removeAllElements(); 145 | m_stateArray = new Array(); 146 | m_transitionArray = new Array(); 147 | m_arrowContainer = new Sprite(); 148 | m_curArrow = null; 149 | m_curState = null; 150 | m_editLayer.addChild(m_arrowContainer); 151 | m_paramArray = new Array(); 152 | m_paramArray.push(new Parameter(Parameter.COMPLETE_ID, Parameter.TYPE_COMPLETE)); 153 | m_armatureInfo = new Object(); 154 | } 155 | 156 | public function initStates(input:Array = null,skeletonName:String = "fsm"):void 157 | { 158 | reset(); 159 | m_skeletonName = skeletonName; 160 | if (input && input.length > 0) 161 | { 162 | for (var i:int = 0; i < input.length; i++) 163 | { 164 | var stateName:String = input[i]["state"]; 165 | var animation:String = input[i]["animation"]; 166 | var isDefault:Boolean = input[i]["default"]; 167 | var state:AnimState = addState(stateName, m_editLayer.width / 2 - 200 + 250*Math.cos(i/input.length*Math.PI-Math.PI*0.75), m_editLayer.height / 2 + 250*Math.sin(i/input.length*Math.PI-Math.PI*0.75)); 168 | state.animation = animation; 169 | if(isDefault){ 170 | setDefaultState(state); 171 | } 172 | } 173 | var anyState:AnimState = addState(AnimState.ANYSTATE_ID, m_editLayer.width / 7 * 3, m_editLayer.height / 2); 174 | } 175 | } 176 | 177 | public function addStates(input:Array):void 178 | { 179 | if (input && input.length > 0) 180 | { 181 | for (var i:int = 0; i < input.length; i++) 182 | { 183 | var stateName:String = input[i]["state"]; 184 | var animation:String = input[i]["animation"]; 185 | var state:AnimState = addState(stateName, m_editLayer.width / 2 - 200 + 250*Math.cos((i+m_stateArray.length)/input.length*Math.PI-Math.PI*0.75), m_editLayer.height / 2 + 250*Math.sin((i+m_stateArray.length)/input.length*Math.PI-Math.PI*0.75)); 186 | state.animation = animation; 187 | } 188 | } 189 | } 190 | 191 | public function set paramArray(value:Array):void 192 | { 193 | m_paramArray = value; 194 | } 195 | 196 | public function get paramArray():Array 197 | { 198 | return m_paramArray; 199 | } 200 | 201 | public function get stateArray():Array 202 | { 203 | return m_stateArray; 204 | } 205 | 206 | public function get skeletonName():String 207 | { 208 | return m_skeletonName; 209 | } 210 | 211 | public function get arrowContainer():Sprite 212 | { 213 | return m_arrowContainer; 214 | } 215 | 216 | public function get curArrow():AnimTransition 217 | { 218 | return m_curArrow; 219 | } 220 | 221 | public function set curArrow(value:AnimTransition):void 222 | { 223 | if (m_curArrow) 224 | { 225 | m_curArrow.isSelected = false; 226 | } 227 | m_curArrow = value; 228 | if (value) 229 | { 230 | value.isSelected = true; 231 | } 232 | updateTransitionInspector(m_curArrow); 233 | } 234 | 235 | public function get curState():AnimState 236 | { 237 | return m_curState; 238 | } 239 | 240 | public function set curState(value:AnimState):void 241 | { 242 | if (m_curState) 243 | { 244 | m_curState.isSelected = false; 245 | } 246 | m_curState = value; 247 | if (value) 248 | { 249 | value.isSelected = true; 250 | } 251 | updateStateInfo(m_curState); 252 | } 253 | 254 | private function checkParamExist(param:Parameter):Boolean 255 | { 256 | for (var i:int = 0; i < m_paramArray.length; i++) 257 | { 258 | var element:Parameter = m_paramArray[i] as Parameter; 259 | if (param.id == element.id) 260 | { 261 | return true; 262 | } 263 | } 264 | return false; 265 | } 266 | 267 | public function addParam(param:Parameter):void 268 | { 269 | if (checkParamExist(param)) 270 | { 271 | if(param.id != Parameter.COMPLETE_ID){ 272 | Alert.show("Parameter Already Exists!"); 273 | } 274 | return; 275 | } 276 | m_paramArray.push(param); 277 | var hGroup:HGroup = new HGroup(); 278 | hGroup.verticalAlign = VerticalAlign.MIDDLE; 279 | var input:TextInput = new TextInput(); 280 | input.text = param.id; 281 | input.addEventListener(TextOperationEvent.CHANGE,function(e:TextOperationEvent):void{ 282 | param.id = e.target.text; 283 | updateTransitionInspector(m_curArrow); 284 | }) 285 | input.width = 60; 286 | var type:DropDownList = new DropDownList(); 287 | type.dataProvider = new ArrayCollection([ 288 | {id:Parameter.TYPE_BOOL,label:'bool'}, 289 | {id:Parameter.TYPE_NUMBER,label:'number'}, 290 | {id:Parameter.TYPE_TRIGGER,label:'trigger'} 291 | ]); 292 | type.width = 80; 293 | type.selectedIndex = param.type - Parameter.TYPE_BOOL; 294 | type.addEventListener(IndexChangeEvent.CHANGING,function(e:IndexChangeEvent):void{ 295 | param.type = type.selectedItem.id; 296 | updateTransitionInspector(m_curArrow); 297 | }); 298 | var remove:Image = new Image(); 299 | remove.source = "assets/-.png"; 300 | remove.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void{ 301 | EditController.getInstance().removeParam(param); 302 | m_paramList.removeElement(hGroup); 303 | updateTransitionInspector(m_curArrow); 304 | }); 305 | hGroup.addElement(input); 306 | hGroup.addElement(type); 307 | hGroup.addElement(remove); 308 | m_paramList.addElement(hGroup); 309 | if (m_paramPanel.height < m_paramPanel.maxHeight) 310 | { 311 | m_paramPanel.height += 30; 312 | } 313 | m_paramScroller.validateNow(); 314 | m_paramScroller.viewport.verticalScrollPosition=m_paramScroller.viewport.contentHeight; 315 | updateTransitionInspector(m_curArrow); 316 | } 317 | 318 | public function removeParam(param:Parameter):void 319 | { 320 | for (var i:int = 0; i < m_paramArray.length; i++) 321 | { 322 | var oneParam:Parameter = m_paramArray[i]; 323 | if(param == oneParam){ 324 | m_paramArray.splice(i,1); 325 | return; 326 | } 327 | } 328 | } 329 | 330 | private function updateTransitionInspector(transition:AnimTransition):void 331 | { 332 | m_inspector.removeAllElements(); 333 | if (transition) 334 | { 335 | for (var i:int = 0; i < transition.conditionArray.length; i++) 336 | { 337 | var element:Condition = transition.conditionArray[i] as Condition; 338 | m_inspector.addElement(createConditionContent(element,transition)); 339 | } 340 | var hGroup:HGroup = new HGroup(); 341 | var add:Button = new Button(); 342 | add.width = 150; 343 | add.label = "+ Add Condition"; 344 | add.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void{ 345 | transition.addCondition(); 346 | updateTransitionInspector(transition); 347 | }); 348 | hGroup.addElement(add); 349 | m_inspector.addElement(add); 350 | } 351 | } 352 | 353 | private function createConditionContent(condition:Condition,transition:AnimTransition):HGroup 354 | { 355 | var hGroup:HGroup = new HGroup(); 356 | hGroup.verticalAlign = VerticalAlign.MIDDLE; 357 | var type:DropDownList = new DropDownList(); 358 | var array:Array = new Array(); 359 | for (var i:int = 0; i < m_paramArray.length; i++) 360 | { 361 | var param:Parameter = m_paramArray[i] as Parameter; 362 | array.push({label:param.id, parameter:param}); 363 | if(condition.id == param.id){ 364 | type.selectedIndex = i; 365 | } 366 | } 367 | type.dataProvider = new ArrayCollection(array); 368 | type.width = 90; 369 | type.addEventListener(IndexChangeEvent.CHANGING,function(e:IndexChangeEvent):void{ 370 | changeParameter(condition,transition,hGroup,type.selectedItem.parameter); 371 | }); 372 | hGroup.addElement(type); 373 | changeParameter(condition,transition,hGroup,condition.parameter); 374 | return hGroup; 375 | } 376 | 377 | private function changeParameter(condition:Condition,transition:AnimTransition,hGroup:HGroup,param:Parameter):void 378 | { 379 | condition.parameter = param; 380 | for (var i:int = 0; i < hGroup.numElements; i++) 381 | { 382 | var element:SkinnableComponent = hGroup.getElementAt(i) as SkinnableComponent; 383 | if (element.id == LOGIC_ID || element.id == VALUE_ID || element.id == REMOVE_ID || element.id == INPUT_ID) 384 | { 385 | hGroup.removeElementAt(i); 386 | i--; 387 | } 388 | } 389 | switch(param.type) 390 | { 391 | case Parameter.TYPE_BOOL: 392 | { 393 | var boolValue:DropDownList = new DropDownList(); 394 | boolValue.dataProvider = new ArrayCollection([ 395 | {id:0,label:'false'}, 396 | {id:1,label:'true'} 397 | ]); 398 | boolValue.width = 65; 399 | boolValue.id = VALUE_ID; 400 | boolValue.addEventListener(IndexChangeEvent.CHANGING,function(e:IndexChangeEvent):void{ 401 | condition.value = boolValue.selectedItem.id; 402 | }) 403 | hGroup.addElement(boolValue); 404 | condition.logic = Condition.LOGIC_EQUAL; 405 | boolValue.selectedIndex = condition.value; 406 | break; 407 | } 408 | case Parameter.TYPE_NUMBER: 409 | { 410 | var numLogic:DropDownList = new DropDownList(); 411 | numLogic.dataProvider = new ArrayCollection([ 412 | {id:Condition.LOGIC_EQUAL,label:'='}, 413 | {id:Condition.LOGIC_GREATER,label:'>'}, 414 | {id:Condition.LOGIC_LESS,label:'<'}, 415 | {id:Condition.LOGIC_NOTEQUAL,label:'≠'} 416 | ]); 417 | numLogic.width = 65; 418 | numLogic.addEventListener(IndexChangeEvent.CHANGING,function(e:IndexChangeEvent):void{ 419 | condition.logic = numLogic.selectedItem.id;; 420 | }); 421 | var numValue:TextInput = new TextInput(); 422 | numValue.width = 50; 423 | numValue.id = VALUE_ID; 424 | numValue.text = condition.value.toString(); 425 | numValue.addEventListener(TextOperationEvent.CHANGE,function(e:TextOperationEvent):void{ 426 | condition.value = parseInt(e.target.text); 427 | }) 428 | numLogic.id = LOGIC_ID; 429 | hGroup.addElement(numLogic); 430 | hGroup.addElement(numValue); 431 | numLogic.selectedIndex = condition.logic; 432 | break; 433 | } 434 | case Parameter.TYPE_TRIGGER: 435 | { 436 | break; 437 | } 438 | case Parameter.TYPE_COMPLETE: 439 | { 440 | break; 441 | } 442 | default: 443 | { 444 | break; 445 | } 446 | } 447 | var remove:Image = new Image(); 448 | remove.source = "assets/-.png"; 449 | remove.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void{ 450 | transition.removeCondition(condition); 451 | updateTransitionInspector(transition); 452 | }); 453 | remove.id = REMOVE_ID; 454 | hGroup.addElement(remove); 455 | } 456 | 457 | public function get editLayer():Sprite 458 | { 459 | return m_editLayer; 460 | } 461 | 462 | public function get inspector():VGroup 463 | { 464 | return m_inspector; 465 | } 466 | 467 | public function setDefaultState(state:AnimState):void 468 | { 469 | if(m_defaultState){ 470 | m_defaultState.isDefaultState = false; 471 | } 472 | state.isDefaultState = true; 473 | m_defaultState = state; 474 | } 475 | 476 | public function getStateById(id:String):AnimState 477 | { 478 | for each (var state:AnimState in m_stateArray) 479 | { 480 | if (state.id == id) 481 | { 482 | return state; 483 | } 484 | } 485 | return null; 486 | } 487 | 488 | public function getStateByMouse(pt:Point):AnimState 489 | { 490 | for each (var state:AnimState in m_stateArray) 491 | { 492 | var rect:Rectangle = state.getRect(state); 493 | var point:Point = state.globalToLocal(pt); 494 | if (rect.containsPoint(point)) 495 | { 496 | return state; 497 | } 498 | } 499 | return null; 500 | } 501 | 502 | public function updateStateInfo(state:AnimState):void 503 | { 504 | m_stateInputer.text = state.id; 505 | m_animationInputer.text = state.animation; 506 | } 507 | 508 | public function makeTransition(state:AnimState,addDefaultCondition:Boolean = true):AnimTransition 509 | { 510 | var transition:AnimTransition = new AnimTransition(state); 511 | m_transitionArray.push(transition); 512 | if (addDefaultCondition) 513 | { 514 | transition.addCondition(); 515 | } 516 | return transition; 517 | } 518 | 519 | public function updateArrow(state:AnimState):void 520 | { 521 | for each (var transition:AnimTransition in m_transitionArray) 522 | { 523 | if(transition.from == state || transition.to == state){ 524 | transition.draw(); 525 | } 526 | } 527 | } 528 | 529 | public function checkTransitionExist(transition:AnimTransition):void 530 | { 531 | for each (var oneTransition:AnimTransition in m_transitionArray) 532 | { 533 | if(oneTransition != transition && oneTransition.from == transition.from && oneTransition.to == transition.to){ 534 | removeTransition(transition); 535 | Alert.show("Transition Already Exists!") 536 | return; 537 | } 538 | } 539 | } 540 | 541 | public function removeTransition(transition:AnimTransition):void 542 | { 543 | for (var i:int = 0; i < m_transitionArray.length; i++) 544 | { 545 | var oneTransition:AnimTransition = m_transitionArray[i]; 546 | if(oneTransition == transition){ 547 | m_transitionArray.splice(i,1); 548 | oneTransition.destroy(); 549 | return; 550 | } 551 | } 552 | } 553 | 554 | public function hasDragState():Boolean 555 | { 556 | for each (var state:AnimState in m_stateArray) 557 | { 558 | if (state.isDrag) 559 | { 560 | return true; 561 | } 562 | } 563 | return false; 564 | } 565 | 566 | public function get armatureInfo():Object 567 | { 568 | return m_armatureInfo; 569 | } 570 | 571 | public function set armatureInfo(value:Object):void 572 | { 573 | m_armatureInfo = value; 574 | } 575 | 576 | public function save():void 577 | { 578 | DataParser.saveFsmJson(m_skeletonName, m_stateArray, m_transitionArray, m_paramArray, m_armatureInfo); 579 | } 580 | } 581 | } -------------------------------------------------------------------------------- /src/com/wonder/Parameter.as: -------------------------------------------------------------------------------- 1 | package com.wonder 2 | { 3 | public class Parameter 4 | { 5 | public static var COMPLETE_ID:String = "complete"; 6 | public static var DEFAULT_ID:String = "unused"; 7 | 8 | public static var TYPE_COMPLETE:int = 0; 9 | public static var TYPE_BOOL:int = 1; 10 | public static var TYPE_NUMBER:int = 2; 11 | public static var TYPE_TRIGGER:int = 3; 12 | 13 | private var m_id:String = null; 14 | private var m_type:int = 0; 15 | 16 | public function Parameter(id:String="unused",type:int=3) 17 | { 18 | m_id = id; 19 | m_type = type; 20 | } 21 | 22 | public function get id():String 23 | { 24 | return m_id; 25 | } 26 | 27 | public function set id(value:String):void 28 | { 29 | m_id = value; 30 | } 31 | 32 | public function get type():int 33 | { 34 | return m_type; 35 | } 36 | 37 | public function set type(value:int):void 38 | { 39 | m_type = value; 40 | } 41 | } 42 | } --------------------------------------------------------------------------------