1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * The Cocostudio's action node, it contains action target, action frame list and current frame index.  it can be play action by calling playAciton.
 28  * @class
 29  * @extends ccs.Class
 30  */
 31 ccs.ActionNode = ccs.Class.extend(/** @lends ccs.ActionNode# */{
 32     _currentFrameIndex: 0,
 33     _destFrameIndex: 0,
 34     _unitTime: 0,
 35     _actionTag: 0,
 36     _object: null,
 37     _actionSpawn: null,
 38     _action: null,
 39     _frameArray: null,
 40     _frameArrayNum: 0,
 41 
 42     /**
 43      * Construction of ccs.ActionNode
 44      */
 45     ctor: function () {
 46         this._currentFrameIndex = 0;
 47         this._destFrameIndex = 0;
 48         this._unitTime = 0.1;
 49         this._actionTag = 0;
 50         this._object = null;
 51         this._actionSpawn = null;
 52         this._action = null;
 53         this._frameArray = [];
 54         this._frameArrayNum = ccs.FRAME_TYPE_MAX;
 55         for (var i = 0; i < this._frameArrayNum; i++)
 56             this._frameArray.push([]);
 57     },
 58 
 59     /**
 60      *  Init properties with a json dictionary
 61      * @param {Object} dic
 62      * @param {Object} root
 63      */
 64     initWithDictionary: function (dic, root) {
 65         this.setActionTag(dic["ActionTag"]);
 66         var actionFrameList = dic["actionframelist"];
 67         for (var i = 0; i < actionFrameList.length; i++) {
 68             var actionFrameDic = actionFrameList[i];
 69             var frameIndex = actionFrameDic["frameid"];
 70             var frameTweenType = actionFrameDic["tweenType"];
 71             if(frameTweenType == null)
 72                 frameTweenType = 0;
 73             var frameTweenParameterNum = actionFrameDic["tweenParameter"];
 74 
 75             var frameTweenParameter = [];
 76             for (var j = 0; j < frameTweenParameterNum; j++){
 77                 var value = actionFrameDic["tweenParameter"][j];
 78                 frameTweenParameter.push(value);
 79             }
 80 
 81             var actionFrame, actionArray;
 82             if (actionFrameDic["positionx"] !== undefined) {
 83                 var positionX = actionFrameDic["positionx"];
 84                 var positionY = actionFrameDic["positiony"];
 85                 actionFrame = new ccs.ActionMoveFrame();
 86                 actionFrame.frameIndex = frameIndex;
 87                 actionFrame.setEasingType(frameTweenType);
 88                 actionFrame.setEasingParameter(frameTweenParameter);
 89                 actionFrame.setPosition(positionX, positionY);
 90                 actionArray = this._frameArray[ccs.FRAME_TYPE_MOVE];
 91                 actionArray.push(actionFrame);
 92             }
 93 
 94             if (actionFrameDic["scalex"] !== undefined) {
 95                 var scaleX = actionFrameDic["scalex"];
 96                 var scaleY = actionFrameDic["scaley"];
 97                 actionFrame = new ccs.ActionScaleFrame();
 98                 actionFrame.frameIndex = frameIndex;
 99                 actionFrame.setEasingType(frameTweenType);
100                 actionFrame.setEasingParameter(frameTweenParameter);
101                 actionFrame.setScaleX(scaleX);
102                 actionFrame.setScaleY(scaleY);
103                 actionArray = this._frameArray[ccs.FRAME_TYPE_SCALE];
104                 actionArray.push(actionFrame);
105             }
106 
107             if (actionFrameDic["rotation"] !== undefined) {
108                 var rotation = actionFrameDic["rotation"];
109                 actionFrame = new ccs.ActionRotationFrame();
110                 actionFrame.frameIndex = frameIndex;
111                 actionFrame.setEasingType(frameTweenType);
112                 actionFrame.setEasingParameter(frameTweenParameter);
113                 actionFrame.setRotation(rotation);
114                 actionArray = this._frameArray[ccs.FRAME_TYPE_ROTATE];
115                 actionArray.push(actionFrame);
116             }
117 
118             if (actionFrameDic["opacity"] !== undefined) {
119                 var opacity = actionFrameDic["opacity"];
120                 actionFrame = new ccs.ActionFadeFrame();
121                 actionFrame.frameIndex = frameIndex;
122                 actionFrame.setEasingType(frameTweenType);
123                 actionFrame.setEasingParameter(frameTweenParameter);
124                 actionFrame.setOpacity(opacity);
125                 actionArray = this._frameArray[ccs.FRAME_TYPE_FADE];
126                 actionArray.push(actionFrame);
127             }
128 
129             if (actionFrameDic["colorr"] !== undefined) {
130                 var colorR = actionFrameDic["colorr"];
131                 var colorG = actionFrameDic["colorg"];
132                 var colorB = actionFrameDic["colorb"];
133                 actionFrame = new ccs.ActionTintFrame();
134                 actionFrame.frameIndex = frameIndex;
135                 actionFrame.setEasingType(frameTweenType);
136                 actionFrame.setEasingParameter(frameTweenParameter);
137                 actionFrame.setColor(cc.color(colorR, colorG, colorB));
138                 actionArray = this._frameArray[ccs.FRAME_TYPE_TINT];
139                 actionArray.push(actionFrame);
140             }
141             actionFrameDic = null;
142         }
143         this._initActionNodeFromRoot(root);
144     },
145 
146     _initActionNodeFromRoot: function (root) {
147         if (root instanceof ccui.Widget) {
148             var widget = ccui.helper.seekActionWidgetByActionTag(root, this.getActionTag());
149             if (widget)
150                 this.setObject(widget);
151         }
152     },
153 
154     /**
155      * Sets the time interval of frame.
156      * @param {number} time
157      */
158     setUnitTime: function (time) {
159         this._unitTime = time;
160         this._refreshActionProperty();
161     },
162 
163     /**
164      * Returns the time interval of frame.
165      * @returns {number}
166      */
167     getUnitTime: function () {
168         return this._unitTime;
169     },
170 
171     /**
172      * Sets tag to ccs.ActionNode
173      * @param {Number} tag
174      */
175     setActionTag: function (tag) {
176         this._actionTag = tag;
177     },
178 
179     /**
180      * Returns the tag of ccs.ActionNode
181      * @returns {number}
182      */
183     getActionTag: function () {
184         return this._actionTag;
185     },
186 
187     /**
188      * Sets node which will run a action.
189      * @param {Object} node
190      */
191     setObject: function (node) {
192         this._object = node;
193     },
194 
195     /**
196      * Returns node which will run a action.
197      * @returns {*}
198      */
199     getObject: function () {
200         return this._object;
201     },
202 
203     /**
204      * Returns the target node of ccs.ActionNode
205      * @returns {cc.Node}
206      */
207     getActionNode: function () {
208         if (this._object instanceof cc.Node)
209             return this._object;
210         return null;
211     },
212 
213     /**
214      * Inserts an ActionFrame to ccs.ActionNode.
215      * @param {number} index
216      * @param {ccs.ActionFrame} frame
217      */
218     insertFrame: function (index, frame) {
219         if (frame == null)
220             return;
221         var frameType = frame.frameType;
222         var array = this._frameArray[frameType];
223         array.splice(index, 0, frame);
224     },
225 
226     /**
227      * Pushes back an ActionFrame to ccs.ActionNode.
228      * @param {ccs.ActionFrame} frame
229      */
230     addFrame: function (frame) {
231         if (!frame)
232             return;
233         var frameType = frame.frameType;
234         var array = this._frameArray[frameType];
235         array.push(frame);
236     },
237 
238     /**
239      * Removes an ActionFrame from ccs.ActionNode.
240      * @param {ccs.ActionFrame} frame
241      */
242     deleteFrame: function (frame) {
243         if (frame == null)
244             return;
245         var frameType = frame.frameType;
246         var array = this._frameArray[frameType];
247         cc.arrayRemoveObject(array, frame);
248     },
249 
250     /**
251      * Removes all ActionFrames from ccs.ActionNode.
252      */
253     clearAllFrame: function () {
254         for (var i = 0; i < this._frameArrayNum; i++)
255             this._frameArray[i].length = 0;
256     },
257 
258     _refreshActionProperty: function () {
259         if (this._object == null)
260             return null;
261         var locSpawnArray = [];
262         for (var i = 0; i < this._frameArrayNum; i++) {
263             var locArray = this._frameArray[i];
264             if (locArray.length <= 0)
265                 continue;
266             var locSequenceArray = [];
267             for (var j = 0; j < locArray.length; j++) {
268                 var locFrame = locArray[j];
269                 if (j != 0) {
270                     var locSrcFrame = locArray[j - 1];
271                     var locDuration = (locFrame.frameIndex - locSrcFrame.frameIndex) * this.getUnitTime();
272                     var locAction = locFrame.getAction(locDuration);
273                     if(locAction)
274                         locSequenceArray.push(locAction);
275                 }
276             }
277             if(locSequenceArray){
278                 var locSequence = cc.sequence(locSequenceArray);
279                 if (locSequence != null)
280                     locSpawnArray.push(locSequence);
281             }
282         }
283 
284         this._action = null;
285         this._actionSpawn = cc.spawn(locSpawnArray);
286         return this._actionSpawn;
287     },
288 
289     /**
290      * Plays ccs.ActionNode's action.
291      * @param {cc.CallFunc} fun
292      */
293     playAction: function (fun) {
294         if (this._object == null || this._actionSpawn == null)
295             return;
296         if(fun)
297             this._action = cc.sequence(this._actionSpawn, fun);
298         else
299             this._action = cc.sequence(this._actionSpawn);
300         this._runAction();
301     },
302 
303     _runAction: function () {
304         var node = this.getActionNode();
305         if (node != null && this._action != null)
306             node.runAction(this._action);
307     },
308 
309     /**
310      * Stops action.
311      */
312     stopAction: function () {
313         var node = this.getActionNode();
314         if (node != null && this._action != null) {
315             if(!this._action.isDone())
316                 node.stopAction(this._action);
317         }
318     },
319 
320     /**
321      * Returns index of first ActionFrame.
322      * @returns {number}
323      */
324     getFirstFrameIndex: function () {
325         var locFrameindex = 99999;
326         var bFindFrame = false, locFrameArray = this._frameArray;
327         for (var i = 0, len = this._frameArrayNum; i < len; i++) {
328             var locArray = locFrameArray[i];
329             if (locArray.length <= 0)
330                 continue;
331             bFindFrame = true;
332             var locFrameIndex = locArray[0].frameIndex;
333             locFrameindex = locFrameindex > locFrameIndex ? locFrameIndex : locFrameindex;
334         }
335         if (!bFindFrame)
336             locFrameindex = 0;
337         return locFrameindex;
338     },
339 
340     /**
341      * Returns the index of last ccs.ActionFrame.
342      * @returns {number}
343      */
344     getLastFrameIndex: function () {
345         var locFrameindex = -1;
346         var locIsFindFrame = false ,locFrameArray = this._frameArray;
347         for (var i = 0, len = this._frameArrayNum; i < len; i++) {
348             var locArray = locFrameArray[i];
349             if (locArray.length <= 0)
350                 continue;
351             locIsFindFrame = true;
352             var locFrame = locArray[locArray.length - 1];
353             var locFrameIndex = locFrame.frameIndex;
354             locFrameindex = locFrameindex < locFrameIndex ? locFrameIndex : locFrameindex;
355         }
356         if (!locIsFindFrame)
357             locFrameindex = 0;
358         return locFrameindex;
359     },
360 
361     /**
362      * Updates action states to some time.
363      * @param {Number} time
364      * @returns {boolean}
365      */
366     updateActionToTimeLine: function (time) {
367         var locIsFindFrame = false;
368         var locUnitTime = this.getUnitTime();
369         for (var i = 0; i < this._frameArrayNum; i++) {
370             var locArray = this._frameArray[i];
371             if (locArray == null)
372                 continue;
373 
374             for (var j = 0; j < locArray.length; j++) {
375                 var locFrame = locArray[j];
376                 if (locFrame.frameIndex * locUnitTime == time) {
377                     this._easingToFrame(1.0, 1.0, locFrame);
378                     locIsFindFrame = true;
379                     break;
380                 } else if (locFrame.frameIndex * locUnitTime > time) {
381                     if (j == 0) {
382                         this._easingToFrame(1.0, 1.0, locFrame);
383                         locIsFindFrame = false;
384                     } else {
385                         var locSrcFrame = locArray[j - 1];
386                         var locDuration = (locFrame.frameIndex - locSrcFrame.frameIndex) * locUnitTime;
387                         var locDelaytime = time - locSrcFrame.frameIndex * locUnitTime;
388                         this._easingToFrame(locDuration, 1.0, locSrcFrame);
389                         this._easingToFrame(locDuration, locDelaytime / locDuration, locFrame);
390                         locIsFindFrame = true;
391                     }
392                     break;
393                 }
394             }
395         }
396         return locIsFindFrame;
397     },
398 
399     _easingToFrame: function (duration, delayTime, destFrame) {
400         var action = destFrame.getAction(duration);
401         var node = this.getActionNode();
402         if (action == null || node == null)
403             return;
404         action.startWithTarget(node);
405         action.update(delayTime);
406     },
407 
408     /**
409      * Returns if the action is done once time.
410      * @returns {Boolean} that if the action is done once time
411      */
412     isActionDoneOnce: function () {
413         if (this._action == null)
414             return true;
415         return this._action.isDone();
416     }
417 });