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