1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** Default Action tag 28 * @constant 29 * @type {Number} 30 */ 31 cc.ACTION_TAG_INVALID = -1; 32 33 /** 34 * Base class for cc.Action objects. 35 * @class 36 * @extends cc.Class 37 * 38 * @property {cc.Node} target - The target will be set with the 'startWithTarget' method. When the 'stop' method is called, target will be set to nil. 39 * @property {cc.Node} originalTarget - The original target of the action. 40 * @property {Number} tag - The tag of the action, can be used to find the action. 41 */ 42 cc.Action = cc.Class.extend(/** @lends cc.Action# */{ 43 //***********variables************* 44 originalTarget:null, 45 target:null, 46 tag:cc.ACTION_TAG_INVALID, 47 48 //**************Public Functions*********** 49 ctor:function () { 50 this.originalTarget = null; 51 this.target = null; 52 this.tag = cc.ACTION_TAG_INVALID; 53 }, 54 55 /** 56 * to copy object with deep copy. 57 * @deprecated 58 * @return {object} 59 */ 60 copy:function () { 61 cc.log("copy is deprecated. Please use clone instead."); 62 return this.clone(); 63 }, 64 65 /** 66 * returns a clone of action 67 * @return {cc.Action} 68 */ 69 clone:function () { 70 var action = new cc.Action(); 71 action.originalTarget = null; 72 action.target = null; 73 action.tag = this.tag; 74 return action; 75 }, 76 77 /** 78 * return true if the action has finished 79 * @return {Boolean} 80 */ 81 isDone:function () { 82 return true; 83 }, 84 85 /** 86 * called before the action start. It will also set the target. 87 * @param {cc.Node} target 88 */ 89 startWithTarget:function (target) { 90 this.originalTarget = target; 91 this.target = target; 92 }, 93 94 /** 95 * called after the action has finished. It will set the 'target' to nil. 96 * IMPORTANT: You should never call "action stop" manually. Instead, use: "target.stopAction(action);" 97 */ 98 stop:function () { 99 this.target = null; 100 }, 101 /** called every frame with it's delta time. DON'T override unless you know what you are doing. 102 * 103 * @param {Number} dt 104 */ 105 106 step:function (dt) { 107 cc.log("[Action step]. override me"); 108 }, 109 110 /** 111 <p>called once per frame. time a value between 0 and 1 </P> 112 113 <p>For example: <br/> 114 - 0 means that the action just started <br/> 115 - 0.5 means that the action is in the middle<br/> 116 - 1 means that the action is over </P> 117 * @param {Number} time 118 */ 119 update:function (time) { 120 cc.log("[Action update]. override me"); 121 }, 122 123 /** 124 * 125 * @return {cc.Node} 126 */ 127 getTarget:function () { 128 return this.target; 129 }, 130 131 /** The action will modify the target properties. 132 * 133 * @param {cc.Node} target 134 */ 135 setTarget:function (target) { 136 this.target = target; 137 }, 138 139 /** 140 * 141 * @return {cc.Node} 142 */ 143 getOriginalTarget:function () { 144 return this.originalTarget; 145 }, 146 147 /** Set the original target, since target can be nil. <br/> 148 * Is the target that were used to run the action. <br/> 149 * Unless you are doing something complex, like cc.ActionManager, you should NOT call this method. <br/> 150 * The target is 'assigned', it is not 'retained'. <br/> 151 * @param {cc.Node} originalTarget 152 */ 153 setOriginalTarget:function (originalTarget) { 154 this.originalTarget = originalTarget; 155 }, 156 157 /** 158 * 159 * @return {Number} 160 */ 161 getTag:function () { 162 return this.tag; 163 }, 164 165 /** 166 * 167 * @param {Number} tag 168 */ 169 setTag:function (tag) { 170 this.tag = tag; 171 }, 172 /** 173 * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, 174 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. 175 * This is a hack, and should be removed once JSB fixes the retain/release bug 176 */ 177 retain:function () { 178 }, 179 release:function () { 180 } 181 }); 182 /** Allocates and initializes the action 183 * @function 184 * @returns {cc.Action} 185 * @example 186 * // example 187 * var action = cc.action(); 188 */ 189 cc.action = function () { 190 return new cc.Action(); 191 }; 192 /** 193 * Please use cc.action instead 194 * Allocates and initializes the action 195 * @returns {cc.Action} 196 * @example 197 * @static 198 * @deprecated 199 */ 200 cc.Action.create = cc.action; 201 202 203 /** 204 * <p>Base class actions that do have a finite time duration.<br/> 205 * Possible actions: <br/> 206 * - An action with a duration of 0 seconds<br/> 207 * - An action with a duration of 35.5 seconds </p> 208 209 * Infinite time actions are valid 210 * @class 211 * @extends cc.Action 212 */ 213 cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ 214 //! duration in seconds 215 _duration:0, 216 217 ctor:function () { 218 cc.Action.prototype.ctor.call(this); 219 this._duration = 0; 220 }, 221 222 /** get duration in seconds of the action 223 * 224 * @return {Number} 225 */ 226 getDuration:function () { 227 return this._duration * (this._times || 1); 228 }, 229 230 /** set duration in seconds of the action 231 * 232 * @param {Number} duration 233 */ 234 setDuration:function (duration) { 235 this._duration = duration; 236 }, 237 238 /** returns a reversed action 239 * 240 * @return {Null} 241 */ 242 reverse:function () { 243 cc.log("cocos2d: FiniteTimeAction#reverse: Implement me"); 244 return null; 245 }, 246 247 /** 248 * 249 */ 250 clone:function () { 251 return new cc.FiniteTimeAction(); 252 } 253 }); 254 255 /** 256 * Changes the speed of an action, making it take longer (speed>1) 257 * or less (speed<1) time. <br/> 258 * Useful to simulate 'slow motion' or 'fast forward' effect. 259 * @warning This action can't be Sequenceable because it is not an cc.IntervalAction 260 * @class 261 * @extends cc.Action 262 */ 263 cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ 264 _speed:0.0, 265 _innerAction:null, 266 267 /** 268 * Constructor of cc.Speed 269 * @param {cc.ActionInterval} action 270 * @param {Number} speed 271 */ 272 ctor:function (action, speed) { 273 cc.Action.prototype.ctor.call(this); 274 this._speed = 0; 275 this._innerAction = null; 276 277 action && this.initWithAction(action, speed); 278 }, 279 280 /** 281 * @return {Number} 282 */ 283 getSpeed:function () { 284 return this._speed; 285 }, 286 287 /** alter the speed of the inner function in runtime 288 * @param {Number} speed 289 */ 290 setSpeed:function (speed) { 291 this._speed = speed; 292 }, 293 294 /** initializes the action 295 * @param {cc.ActionInterval} action 296 * @param {Number} speed 297 * @return {Boolean} 298 */ 299 initWithAction:function (action, speed) { 300 if(!action) 301 throw "cc.Speed.initWithAction(): action must be non nil"; 302 303 this._innerAction = action; 304 this._speed = speed; 305 return true; 306 }, 307 308 /** 309 * returns a clone of action 310 * @returns {cc.Speed} 311 */ 312 clone:function () { 313 var action = new cc.Speed(); 314 action.initWithAction(this._innerAction.clone(), this._speed); 315 return action; 316 }, 317 318 /** 319 * @param {cc.Node} target 320 */ 321 startWithTarget:function (target) { 322 cc.Action.prototype.startWithTarget.call(this, target); 323 this._innerAction.startWithTarget(target); 324 }, 325 326 /** 327 * Stop the action 328 */ 329 stop:function () { 330 this._innerAction.stop(); 331 cc.Action.prototype.stop.call(this); 332 }, 333 334 /** 335 * @param {Number} dt 336 */ 337 step:function (dt) { 338 this._innerAction.step(dt * this._speed); 339 }, 340 341 /** 342 * @return {Boolean} 343 */ 344 isDone:function () { 345 return this._innerAction.isDone(); 346 }, 347 348 /** 349 * @return {cc.ActionInterval} 350 */ 351 reverse:function () { 352 return (cc.Speed.create(this._innerAction.reverse(), this._speed)); 353 }, 354 355 /** 356 * 357 * @param {cc.ActionInterval} action 358 */ 359 setInnerAction:function (action) { 360 if (this._innerAction != action) { 361 this._innerAction = action; 362 } 363 }, 364 365 /** 366 * 367 * @return {cc.ActionInterval} 368 */ 369 getInnerAction:function () { 370 return this._innerAction; 371 } 372 }); 373 /** creates the speed action 374 * @function 375 * 376 * @param {cc.ActionInterval} action 377 * @param {Number} speed 378 * @return {cc.Speed} 379 */ 380 cc.speed = function (action, speed) { 381 return new cc.Speed(action, speed); 382 }; 383 /** 384 * Please use cc.speed instead 385 * creates the action 386 * 387 * @param {cc.ActionInterval} action 388 * @param {Number} speed 389 * @return {cc.Speed} 390 * @static 391 * @deprecated 392 */ 393 cc.Speed.create = cc.speed; 394 395 /** 396 * cc.Follow is an action that "follows" a node. 397 398 * @example 399 * //example 400 * //Instead of using cc.Camera as a "follower", use this action instead. 401 * layer.runAction(cc.follow(hero)); 402 403 * @class 404 * @extends cc.Action 405 */ 406 cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ 407 // node to follow 408 _followedNode:null, 409 // whether camera should be limited to certain area 410 _boundarySet:false, 411 // if screen size is bigger than the boundary - update not needed 412 _boundaryFullyCovered:false, 413 // fast access to the screen dimensions 414 _halfScreenSize:null, 415 _fullScreenSize:null, 416 417 /** world leftBoundary 418 * @Type {Number} 419 */ 420 leftBoundary:0.0, 421 /** world rightBoundary 422 * @Type Number 423 */ 424 rightBoundary:0.0, 425 /** world topBoundary 426 * @Type Number 427 */ 428 topBoundary:0.0, 429 /** world bottomBoundary 430 * @Type {Number} 431 */ 432 bottomBoundary:0.0, 433 _worldRect:null, 434 435 /** 436 * creates the action with a set boundary <br/> 437 * creates the action with no boundary set 438 * 439 * Constructor of cc.Follow 440 * @param {cc.Node} followedNode 441 * @param {cc.Rect} rect 442 * @example 443 * // example 444 * // creates the action with a set boundary 445 * var sprite = new cc.Sprite("spriteFileName"); 446 * var followAction = new cc.Follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); 447 * this.runAction(followAction); 448 * 449 * // creates the action with no boundary set 450 * var sprite = new cc.Sprite("spriteFileName"); 451 * var followAction = new cc.Follow(sprite); 452 * this.runAction(followAction); 453 */ 454 ctor:function (followedNode, rect) { 455 cc.Action.prototype.ctor.call(this); 456 this._followedNode = null; 457 this._boundarySet = false; 458 459 this._boundaryFullyCovered = false; 460 this._halfScreenSize = null; 461 this._fullScreenSize = null; 462 463 this.leftBoundary = 0.0; 464 this.rightBoundary = 0.0; 465 this.topBoundary = 0.0; 466 this.bottomBoundary = 0.0; 467 this._worldRect = cc.rect(0, 0, 0, 0); 468 469 if(followedNode) 470 rect ? this.initWithTarget(followedNode, rect) 471 : this.initWithTarget(followedNode); 472 }, 473 474 clone:function () { 475 var action = new cc.Follow(); 476 var locRect = this._worldRect; 477 var rect = new cc.Rect(locRect.x, locRect.y, locRect.width, locRect.height); 478 action.initWithTarget(this._followedNode, rect); 479 return action; 480 }, 481 482 /** 483 * @return {Boolean} 484 */ 485 isBoundarySet:function () { 486 return this._boundarySet; 487 }, 488 489 /** alter behavior - turn on/off boundary 490 * @param {Boolean} value 491 */ 492 setBoudarySet:function (value) { 493 this._boundarySet = value; 494 }, 495 496 /** initializes the action 497 * initializes the action with a set boundary 498 * @param {cc.Node} followedNode 499 * @param {cc.Rect} [rect=] 500 * @return {Boolean} 501 */ 502 initWithTarget:function (followedNode, rect) { 503 if(!followedNode) 504 throw "cc.Follow.initWithAction(): followedNode must be non nil"; 505 506 var _this = this; 507 rect = rect || cc.rect(0, 0, 0, 0); 508 _this._followedNode = followedNode; 509 _this._worldRect = rect; 510 511 _this._boundarySet = !cc._rectEqualToZero(rect); 512 513 _this._boundaryFullyCovered = false; 514 515 var winSize = cc.director.getWinSize(); 516 _this._fullScreenSize = cc.p(winSize.width, winSize.height); 517 _this._halfScreenSize = cc.pMult(_this._fullScreenSize, 0.5); 518 519 if (_this._boundarySet) { 520 _this.leftBoundary = -((rect.x + rect.width) - _this._fullScreenSize.x); 521 _this.rightBoundary = -rect.x; 522 _this.topBoundary = -rect.y; 523 _this.bottomBoundary = -((rect.y + rect.height) - _this._fullScreenSize.y); 524 525 if (_this.rightBoundary < _this.leftBoundary) { 526 // screen width is larger than world's boundary width 527 //set both in the middle of the world 528 _this.rightBoundary = _this.leftBoundary = (_this.leftBoundary + _this.rightBoundary) / 2; 529 } 530 if (_this.topBoundary < _this.bottomBoundary) { 531 // screen width is larger than world's boundary width 532 //set both in the middle of the world 533 _this.topBoundary = _this.bottomBoundary = (_this.topBoundary + _this.bottomBoundary) / 2; 534 } 535 536 if ((_this.topBoundary == _this.bottomBoundary) && (_this.leftBoundary == _this.rightBoundary)) 537 _this._boundaryFullyCovered = true; 538 } 539 return true; 540 }, 541 542 /** 543 * @param {Number} dt 544 */ 545 step:function (dt) { 546 var tempPosX = this._followedNode.x; 547 var tempPosY = this._followedNode.y; 548 tempPosX = this._halfScreenSize.x - tempPosX; 549 tempPosY = this._halfScreenSize.y - tempPosY; 550 551 if (this._boundarySet) { 552 // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased 553 if (this._boundaryFullyCovered) 554 return; 555 556 this.target.setPosition(cc.clampf(tempPosX, this.leftBoundary, this.rightBoundary), cc.clampf(tempPosY, this.bottomBoundary, this.topBoundary)); 557 } else { 558 this.target.setPosition(tempPosX, tempPosY); 559 } 560 }, 561 562 /** 563 * @return {Boolean} 564 */ 565 isDone:function () { 566 return ( !this._followedNode.running ); 567 }, 568 569 /** 570 * Stop the action. 571 */ 572 stop:function () { 573 this.target = null; 574 cc.Action.prototype.stop.call(this); 575 } 576 }); 577 /** creates the action with a set boundary <br/> 578 * creates the action with no boundary set 579 * @function 580 * @param {cc.Node} followedNode 581 * @param {cc.Rect} rect 582 * @return {cc.Follow|Null} returns the cc.Follow object on success 583 * @example 584 * // example 585 * // creates the action with a set boundary 586 * var sprite = cc.Sprite.create("spriteFileName"); 587 * var followAction = cc.follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); 588 * this.runAction(followAction); 589 * 590 * // creates the action with no boundary set 591 * var sprite = cc.Sprite.create("spriteFileName"); 592 * var followAction = cc.follow(sprite); 593 * this.runAction(followAction); 594 */ 595 cc.follow = function (followedNode, rect) { 596 return new cc.Follow(followedNode, rect); 597 }; 598 599 /** 600 * Please use cc.follow instead 601 * creates the action with a set boundary <br/> 602 * creates the action with no boundary set 603 * @param {cc.Node} followedNode 604 * @param {cc.Rect} rect 605 * @return {cc.Follow|Null} returns the cc.Follow object on success 606 * @static 607 * @deprecated 608 */ 609 cc.Follow.create = cc.follow; 610