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  * Base class for ccs.ActionNode
 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     _bject: null,
 37     _actionSpawn: null,
 38     _action: null,
 39     _frameArray: null,
 40     _frameArrayNum: 0,
 41     ctor: function () {
 42         this._currentFrameIndex = 0;
 43         this._destFrameIndex = 0;
 44         this._unitTime = 0.1;
 45         this._actionTag = 0;
 46         this._bject = null;
 47         this._actionSpawn = null;
 48         this._action = null;
 49         this._frameArray = [];
 50         this._frameArrayNum = ccs.FRAME_TYPE_MAX;
 51         for (var i = 0; i < this._frameArrayNum; i++) {
 52             this._frameArray.push([]);
 53         }
 54     },
 55 
 56     /**
 57      *  Init properties with a json dictionary
 58      * @param {Object} dic
 59      * @param {Object} root
 60      */
 61     initWithDictionary: function (dic, root) {
 62         this.setActionTag(dic["ActionTag"]);
 63         var actionframelist = dic["actionframelist"];
 64         for (var i = 0; i < actionframelist.length; i++) {
 65             var actionFrameDic = actionframelist[i];
 66             var frameInex = actionFrameDic["frameid"];
 67             var frameTweenType = actionFrameDic["tweenType"];
 68             if(frameTweenType == null)
 69                 frameTweenType = 0;
 70             var frameTweenParameterNum = actionFrameDic["tweenParameter"];
 71 
 72             var frameTweenParameter = [];
 73             for (var j = 0; j < frameTweenParameterNum; j++){
 74                 var value = actionFrameDic["tweenParameter"][j];
 75                 frameTweenParameter.push(value);
 76             }
 77 
 78             var actionFrame, actionArray;
 79             if (actionFrameDic["positionx"] !== undefined) {
 80                 var positionX = actionFrameDic["positionx"];
 81                 var positionY = actionFrameDic["positiony"];
 82                 actionFrame = new ccs.ActionMoveFrame();
 83                 actionFrame.frameIndex = frameInex;
 84                 actionFrame.setEasingType(frameTweenType);
 85                 actionFrame.setEasingParameter(frameTweenParameter);
 86                 actionFrame.setPosition(positionX, positionY);
 87                 actionArray = this._frameArray[ccs.FRAME_TYPE_MOVE];
 88                 actionArray.push(actionFrame);
 89             }
 90 
 91             if (actionFrameDic["scalex"] !== undefined) {
 92                 var scaleX = actionFrameDic["scalex"];
 93                 var scaleY = actionFrameDic["scaley"];
 94                 actionFrame = new ccs.ActionScaleFrame();
 95                 actionFrame.frameIndex = frameInex;
 96                 actionFrame.setEasingType(frameTweenType);
 97                 actionFrame.setEasingParameter(frameTweenParameter);
 98                 actionFrame.setScaleX(scaleX);
 99                 actionFrame.setScaleY(scaleY);
100                 actionArray = this._frameArray[ccs.FRAME_TYPE_SCALE];
101                 actionArray.push(actionFrame);
102             }
103 
104             if (actionFrameDic["rotation"] !== undefined) {
105                 var rotation = actionFrameDic["rotation"];
106                 actionFrame = new ccs.ActionRotationFrame();
107                 actionFrame.frameIndex = frameInex;
108                 actionFrame.setEasingType(frameTweenType);
109                 actionFrame.setEasingParameter(frameTweenParameter);
110                 actionFrame.setRotation(rotation);
111                 actionArray = this._frameArray[ccs.FRAME_TYPE_ROTATE];
112                 actionArray.push(actionFrame);
113             }
114 
115             if (actionFrameDic["opacity"] !== undefined) {
116                 var opacity = actionFrameDic["opacity"];
117                 actionFrame = new ccs.ActionFadeFrame();
118                 actionFrame.frameIndex = frameInex;
119                 actionFrame.setEasingType(frameTweenType);
120                 actionFrame.setEasingParameter(frameTweenParameter);
121                 actionFrame.setOpacity(opacity);
122                 actionArray = this._frameArray[ccs.FRAME_TYPE_FADE];
123                 actionArray.push(actionFrame);
124             }
125 
126             if (actionFrameDic["colorr"] !== undefined) {
127                 var colorR = actionFrameDic["colorr"];
128                 var colorG = actionFrameDic["colorg"];
129                 var colorB = actionFrameDic["colorb"];
130                 actionFrame = new ccs.ActionTintFrame();
131                 actionFrame.frameIndex = frameInex;
132                 actionFrame.setEasingType(frameTweenType);
133                 actionFrame.setEasingParameter(frameTweenParameter);
134                 actionFrame.setColor(cc.color(colorR, colorG, colorB));
135                 actionArray = this._frameArray[ccs.FRAME_TYPE_TINT];
136                 actionArray.push(actionFrame);
137             }
138             actionFrameDic = null;
139         }
140         this.initActionNodeFromRoot(root);
141     },
142 
143     initActionNodeFromRoot: function (root) {
144         if (root instanceof ccui.Widget) {
145             var widget = ccui.helper.seekActionWidgetByActionTag(root, this.getActionTag());
146             if (widget) {
147                 this.setObject(widget);
148             }
149         }
150     },
151 
152     /**
153      * Sets the time interval of frame.
154      * @param {number} time
155      */
156     setUnitTime: function (time) {
157         this._unitTime = time;
158         this.refreshActionProperty();
159     },
160 
161     /**
162      * Gets the time interval of frame.
163      * @returns {number}
164      */
165     getUnitTime: function () {
166         return this._unitTime;
167     },
168 
169     /**
170      * Sets tag for ActionNode
171      * @param tag
172      */
173     setActionTag: function (tag) {
174         this._actionTag = tag;
175     },
176 
177     /**
178      * Gets tag for ActionNode
179      * @returns {number}
180      */
181     getActionTag: function () {
182         return this._actionTag;
183     },
184 
185     /**
186      * Sets node which will run a action.
187      * @param {Object} node
188      */
189     setObject: function (node) {
190         this._object = node;
191     },
192 
193     /**
194      * Gets node which will run a action.
195      * @returns {*}
196      */
197     getObject: function () {
198         return this._object;
199     },
200 
201     /**
202      * get actionNode
203      * @returns {cc.Node}
204      */
205     getActionNode: function () {
206         if (this._object instanceof cc.Node) {
207             return this._object;
208         }
209         else if (this._object instanceof ccui.Widget) {
210             return this._object;
211         }
212         return null;
213     },
214 
215     /**
216      * Insets a ActionFrame to ActionNode.
217      * @param {number} index
218      * @param {ccs.ActionFrame} frame
219      */
220     insertFrame: function (index, frame) {
221         if (frame == null) {
222             return;
223         }
224         var frameType = frame.frameType;
225         var array = this._frameArray[frameType];
226         array.splice(index, 0, frame);
227     },
228 
229     /**
230      * Pushs back a ActionFrame to ActionNode.
231      * @param {ccs.ActionFrame} frame
232      */
233     addFrame: function (frame) {
234         if (!frame) {
235             return;
236         }
237         var frameType = frame.frameType;
238         var array = this._frameArray[frameType];
239         array.push(frame);
240     },
241 
242     /**
243      * Remove a ActionFrame from ActionNode.
244      * @param {ccs.ActionFrame} frame
245      */
246     deleteFrame: function (frame) {
247         if (frame == null) {
248             return;
249         }
250         var frameType = frame.frameType;
251         var array = this._frameArray[frameType];
252         cc.arrayRemoveObject(array, frame);
253     },
254 
255     /**
256      * Remove all ActionFrames from ActionNode.
257      */
258     clearAllFrame: function () {
259         for (var i = 0; i < this._frameArrayNum; i++) {
260             this._frameArray[i] = [];
261         }
262     },
263 
264     /**
265      * Refresh  property of action
266      * @returns {null}
267      */
268     refreshActionProperty: function () {
269         if (this._object == null) {
270             return null;
271         }
272         var locSpawnArray = [];
273         for (var i = 0; i < this._frameArrayNum; i++) {
274             var locArray = this._frameArray[i];
275             if (locArray.length <= 0) {
276                 continue;
277             }
278             var locSequenceArray = [];
279             for (var j = 0; j < locArray.length; j++) {
280                 var locFrame = locArray[j];
281                 if (j != 0) {
282                     var locSrcFrame = locArray[j - 1];
283                     var locDuration = (locFrame.frameIndex - locSrcFrame.frameIndex) * this.getUnitTime();
284                     var locAction = locFrame.getAction(locDuration);
285                     if(locAction){
286                         locSequenceArray.push(locAction);
287                     }
288                 }
289             }
290             if(locSequenceArray){
291                 var locSequence = cc.sequence(locSequenceArray);
292                 if (locSequence != null) {
293                     locSpawnArray.push(locSequence);
294                 }
295             }
296         }
297 
298         this._action = null;
299         this._actionSpawn = cc.spawn(locSpawnArray);
300         return this._actionSpawn;
301     },
302 
303     /**
304      * Play the action.
305      * @param {cc.CallFunc} fun
306      */
307     playAction: function (fun) {
308         if (this._object == null || this._actionSpawn == null) {
309             return;
310         }
311         if(fun){
312             this._action = cc.sequence(this._actionSpawn,fun);
313         }else{
314             this._action = cc.sequence(this._actionSpawn);
315         }
316         this.runAction();
317     },
318 
319     /**
320      * Run action.
321      */
322     runAction: function () {
323         var node = this.getActionNode();
324         if (node != null && this._action != null) {
325             node.runAction(this._action);
326         }
327     },
328 
329     /**
330      * Stop action.
331      */
332     stopAction: function () {
333         var node = this.getActionNode();
334         if (node != null && this._action != null) {
335             if(!this._action.isDone())
336                 node.stopAction(this._action);
337         }
338     },
339 
340     /**
341      * Gets index of first ActionFrame.
342      * @returns {number}
343      */
344     getFirstFrameIndex: function () {
345         var locFrameindex = 99999;
346         var locIsFindFrame = false;
347         for (var i = 0; i < this._frameArrayNum; i++) {
348             var locArray = this._frameArray[i];
349             if (locArray.length <= 0) {
350                 continue;
351             }
352             locIsFindFrame = true;
353             var locFrame = locArray[0];
354             var locFrameIndex = locFrame.frameIndex;
355             locFrameindex = locFrameindex > locFrameIndex ? locFrameIndex : locFrameindex;
356         }
357         if (!locIsFindFrame) {
358             locFrameindex = 0;
359         }
360         return locFrameindex;
361     },
362 
363     /**
364      * Gets index of last ActionFrame.
365      * @returns {number}
366      */
367     getLastFrameIndex: function () {
368         var locFrameindex = -1;
369         var locIsFindFrame = false;
370         for (var i = 0; i < this._frameArrayNum; i++) {
371             var locArray = this._frameArray[i];
372             if (locArray.length <= 0) {
373                 continue;
374             }
375             locIsFindFrame = true;
376             var locFrame = locArray[locArray.length - 1];
377             var locFrameIndex = locFrame.frameIndex;
378             locFrameindex = locFrameindex < locFrameIndex ? locFrameIndex : locFrameindex;
379         }
380         if (!locIsFindFrame) {
381             locFrameindex = 0;
382         }
383         return locFrameindex;
384     },
385 
386     /**
387      * Updates action states to some time.
388      * @param time
389      * @returns {boolean}
390      */
391     updateActionToTimeLine: function (time) {
392         var locIsFindFrame = false;
393         var locUnitTime = this.getUnitTime();
394         for (var i = 0; i < this._frameArrayNum; i++) {
395             var locArray = this._frameArray[i];
396             if (locArray == null) {
397                 continue;
398             }
399 
400             for (var j = 0; j < locArray.length; j++) {
401                 var locFrame = locArray[j];
402                 if (locFrame.frameIndex * locUnitTime == time) {
403                     this.easingToFrame(1.0, 1.0, locFrame);
404                     locIsFindFrame = true;
405                     break;
406                 }
407                 else if (locFrame.frameIndex * locUnitTime > time) {
408                     if (j == 0) {
409                         this.easingToFrame(1.0, 1.0, locFrame);
410                         locIsFindFrame = false;
411                     }
412                     else {
413                         var locSrcFrame = locArray[j - 1];
414                         var locDuration = (locFrame.frameIndex - locSrcFrame.frameIndex) * locUnitTime;
415                         var locDelaytime = time - locSrcFrame.frameIndex * locUnitTime;
416                         this.easingToFrame(locDuration, 1.0, locSrcFrame);
417                         this.easingToFrame(locDuration, locDelaytime / locDuration, locFrame);
418                         locIsFindFrame = true;
419                     }
420                     break;
421                 }
422             }
423         }
424         return locIsFindFrame;
425     },
426 
427     /**
428      * Easing to frame
429      * @param {number} duration
430      * @param {number} delayTime
431      * @param {ccs.ActionFrame} destFrame
432      */
433     easingToFrame: function (duration, delayTime, destFrame) {
434         var action = destFrame.getAction(duration);
435         var node = this.getActionNode();
436         if (action == null || node == null) {
437             return;
438         }
439         action.startWithTarget(node);
440         action.update(delayTime);
441     },
442 
443     isActionDoneOnce: function () {
444         if (this._action == null) {
445             return true;
446         }
447         return this._action.isDone();
448     }
449 });