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 * @default 31 */ 32 cc.ACTION_TAG_INVALID = -1; 33 34 /** 35 * Base class for cc.Action objects. 36 * @class 37 * 38 * @extends cc.Class 39 * 40 * @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. 41 * @property {cc.Node} originalTarget - The original target of the action. 42 * @property {Number} tag - The tag of the action, can be used to find the action. 43 */ 44 cc.Action = cc.Class.extend(/** @lends cc.Action# */{ 45 //***********variables************* 46 originalTarget:null, 47 target:null, 48 tag:cc.ACTION_TAG_INVALID, 49 50 //**************Public Functions*********** 51 52 /** 53 * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 54 */ 55 ctor:function () { 56 this.originalTarget = null; 57 this.target = null; 58 this.tag = cc.ACTION_TAG_INVALID; 59 }, 60 61 /** 62 * to copy object with deep copy. 63 * 64 * @deprecated since v3.0 please use .clone 65 * 66 * @return {cc.Action} 67 */ 68 copy:function () { 69 cc.log("copy is deprecated. Please use clone instead."); 70 return this.clone(); 71 }, 72 73 /** 74 * to copy object with deep copy. 75 * returns a clone of action. 76 * 77 * @return {cc.Action} 78 */ 79 clone:function () { 80 var action = new cc.Action(); 81 action.originalTarget = null; 82 action.target = null; 83 action.tag = this.tag; 84 return action; 85 }, 86 87 /** 88 * return true if the action has finished. 89 * 90 * @return {Boolean} 91 */ 92 isDone:function () { 93 return true; 94 }, 95 96 /** 97 * called before the action start. It will also set the target. 98 * 99 * @param {cc.Node} target 100 */ 101 startWithTarget:function (target) { 102 this.originalTarget = target; 103 this.target = target; 104 }, 105 106 /** 107 * called after the action has finished. It will set the 'target' to nil. <br /> 108 * IMPORTANT: You should never call "action stop" manually. Instead, use: "target.stopAction(action);" 109 */ 110 stop:function () { 111 this.target = null; 112 }, 113 114 /** 115 * called every frame with it's delta time. <br /> 116 * DON'T override unless you know what you are doing. 117 * 118 * @param {Number} dt 119 */ 120 step:function (dt) { 121 cc.log("[Action step]. override me"); 122 }, 123 124 /** 125 * Called once per frame. Time is the number of seconds of a frame interval. 126 * 127 * @param {Number} dt 128 */ 129 update:function (dt) { 130 cc.log("[Action update]. override me"); 131 }, 132 133 /** 134 * get the target. 135 * 136 * @return {cc.Node} 137 */ 138 getTarget:function () { 139 return this.target; 140 }, 141 142 /** 143 * The action will modify the target properties. 144 * 145 * @param {cc.Node} target 146 */ 147 setTarget:function (target) { 148 this.target = target; 149 }, 150 151 /** 152 * get the original target. 153 * 154 * @return {cc.Node} 155 */ 156 getOriginalTarget:function () { 157 return this.originalTarget; 158 }, 159 160 /** 161 * Set the original target, since target can be nil. <br/> 162 * Is the target that were used to run the action. <br/> 163 * Unless you are doing something complex, like cc.ActionManager, you should NOT call this method. <br/> 164 * The target is 'assigned', it is not 'retained'. <br/> 165 * @param {cc.Node} originalTarget 166 */ 167 setOriginalTarget:function (originalTarget) { 168 this.originalTarget = originalTarget; 169 }, 170 171 /** 172 * get tag number. 173 * @return {Number} 174 */ 175 getTag:function () { 176 return this.tag; 177 }, 178 179 /** 180 * set tag number. 181 * @param {Number} tag 182 */ 183 setTag:function (tag) { 184 this.tag = tag; 185 }, 186 187 /** 188 * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, <br/> 189 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. <br/> 190 * This is a hack, and should be removed once JSB fixes the retain/release bug. 191 */ 192 retain:function () { 193 }, 194 195 /** 196 * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, <br/> 197 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. <br/> 198 * This is a hack, and should be removed once JSB fixes the retain/release bug. 199 */ 200 release:function () { 201 } 202 }); 203 204 /** 205 * Allocates and initializes the action. 206 * 207 * @function cc.action 208 * @static 209 * @return {cc.Action} 210 * 211 * @example 212 * // return {cc.Action} 213 * var action = cc.action(); 214 */ 215 cc.action = function () { 216 return new cc.Action(); 217 }; 218 219 /** 220 * Please use cc.action instead. <br/> 221 * Allocates and initializes the action. 222 * 223 * @deprecated since v3.0 please use cc.action() instead. 224 * @static 225 * @returns {cc.Action} 226 */ 227 cc.Action.create = cc.action; 228 229 230 /** 231 * Base class actions that do have a finite time duration. <br/> 232 * Possible actions: <br/> 233 * - An action with a duration of 0 seconds. <br/> 234 * - An action with a duration of 35.5 seconds. 235 * 236 * Infinite time actions are valid 237 * @class 238 * @extends cc.Action 239 */ 240 cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ 241 //! duration in seconds 242 _duration:0, 243 244 /** 245 * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 246 */ 247 ctor:function () { 248 cc.Action.prototype.ctor.call(this); 249 this._duration = 0; 250 }, 251 252 /** 253 * get duration of the action. (seconds) 254 * 255 * @return {Number} 256 */ 257 getDuration:function () { 258 return this._duration * (this._timesForRepeat || 1); 259 }, 260 261 /** 262 * set duration of the action. (seconds) 263 * 264 * @param {Number} duration 265 */ 266 setDuration:function (duration) { 267 this._duration = duration; 268 }, 269 270 /** 271 * Returns a reversed action. <br /> 272 * For example: <br /> 273 * - The action will be x coordinates of 0 move to 100. <br /> 274 * - The reversed action will be x of 100 move to 0. 275 * - Will be rewritten 276 * 277 * @return {Null} 278 */ 279 reverse:function () { 280 cc.log("cocos2d: FiniteTimeAction#reverse: Implement me"); 281 return null; 282 }, 283 284 /** 285 * to copy object with deep copy. 286 * returns a clone of action. 287 * 288 * @return {cc.FiniteTimeAction} 289 */ 290 clone:function () { 291 return new cc.FiniteTimeAction(); 292 } 293 }); 294 295 /** 296 * Changes the speed of an action, making it take longer (speed > 1) 297 * or less (speed < 1) time. <br/> 298 * Useful to simulate 'slow motion' or 'fast forward' effect. 299 * 300 * @warning This action can't be Sequenceable because it is not an cc.IntervalAction 301 * @class 302 * @extends cc.Action 303 * @param {cc.ActionInterval} action 304 * @param {Number} speed 305 */ 306 cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ 307 _speed:0.0, 308 _innerAction:null, 309 310 /** 311 * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 312 * @param {cc.ActionInterval} action 313 * @param {Number} speed 314 */ 315 ctor:function (action, speed) { 316 cc.Action.prototype.ctor.call(this); 317 this._speed = 0; 318 this._innerAction = null; 319 320 action && this.initWithAction(action, speed); 321 }, 322 323 /** 324 * Gets the current running speed. <br /> 325 * Will get a percentage number, compared to the original speed. 326 * 327 * @return {Number} 328 */ 329 getSpeed:function () { 330 return this._speed; 331 }, 332 333 /** 334 * alter the speed of the inner function in runtime. 335 * 336 * @param {Number} speed 337 */ 338 setSpeed:function (speed) { 339 this._speed = speed; 340 }, 341 342 /** 343 * initializes the action. 344 * 345 * @param {cc.ActionInterval} action 346 * @param {Number} speed 347 * @return {Boolean} 348 */ 349 initWithAction:function (action, speed) { 350 if(!action) 351 throw new Error("cc.Speed.initWithAction(): action must be non nil"); 352 353 this._innerAction = action; 354 this._speed = speed; 355 return true; 356 }, 357 358 /** 359 * to copy object with deep copy. 360 * returns a clone of action. 361 * 362 * @returns {cc.Speed} 363 */ 364 clone:function () { 365 var action = new cc.Speed(); 366 action.initWithAction(this._innerAction.clone(), this._speed); 367 return action; 368 }, 369 370 /** 371 * called before the action start. It will also set the target. 372 * 373 * @param {cc.Node} target 374 */ 375 startWithTarget:function (target) { 376 cc.Action.prototype.startWithTarget.call(this, target); 377 this._innerAction.startWithTarget(target); 378 }, 379 380 /** 381 * Stop the action. 382 */ 383 stop:function () { 384 this._innerAction.stop(); 385 cc.Action.prototype.stop.call(this); 386 }, 387 388 /** 389 * called every frame with it's delta time. <br /> 390 * DON'T override unless you know what you are doing. 391 * 392 * @param {Number} dt 393 */ 394 step:function (dt) { 395 this._innerAction.step(dt * this._speed); 396 }, 397 398 /** 399 * return true if the action has finished. 400 * 401 * @return {Boolean} 402 */ 403 isDone:function () { 404 return this._innerAction.isDone(); 405 }, 406 407 /** 408 * returns a reversed action. <br /> 409 * For example: <br /> 410 * - The action will be x coordinates of 0 move to 100. <br /> 411 * - The reversed action will be x of 100 move to 0. 412 * - Will be rewritten 413 * 414 * @return {cc.Speed} 415 */ 416 reverse:function () { 417 return new cc.Speed(this._innerAction.reverse(), this._speed); 418 }, 419 420 /** 421 * Set inner Action. 422 * @param {cc.ActionInterval} action 423 */ 424 setInnerAction:function (action) { 425 if (this._innerAction !== action) { 426 this._innerAction = action; 427 } 428 }, 429 430 /** 431 * Get inner Action. 432 * 433 * @return {cc.ActionInterval} 434 */ 435 getInnerAction:function () { 436 return this._innerAction; 437 } 438 }); 439 440 /** 441 * creates the speed action. 442 * 443 * @function cc.speed 444 * @param {cc.ActionInterval} action 445 * @param {Number} speed 446 * @return {cc.Speed} 447 */ 448 cc.speed = function (action, speed) { 449 return new cc.Speed(action, speed); 450 }; 451 452 /** 453 * Please use cc.speed instead. 454 * creates the action. 455 * 456 * @param {cc.ActionInterval} action 457 * @param {Number} speed 458 * @return {cc.Speed} 459 * @static 460 * @deprecated since v3.0 please use cc.speed() instead. 461 */ 462 cc.Speed.create = cc.speed; 463 464 /** 465 * cc.Follow is an action that "follows" a node. 466 * 467 * @example 468 * //example 469 * //Instead of using cc.Camera as a "follower", use this action instead. 470 * layer.runAction(cc.follow(hero)); 471 * 472 * @property {Number} leftBoundary - world leftBoundary. 473 * @property {Number} rightBoundary - world rightBoundary. 474 * @property {Number} topBoundary - world topBoundary. 475 * @property {Number} bottomBoundary - world bottomBoundary. 476 * 477 * @param {cc.Node} followedNode 478 * @param {cc.Rect} rect 479 * @example 480 * // creates the action with a set boundary 481 * var sprite = new cc.Sprite("spriteFileName"); 482 * var followAction = new cc.Follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); 483 * this.runAction(followAction); 484 * 485 * // creates the action with no boundary set 486 * var sprite = new cc.Sprite("spriteFileName"); 487 * var followAction = new cc.Follow(sprite); 488 * this.runAction(followAction); 489 * 490 * @class 491 * @extends cc.Action 492 */ 493 cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ 494 // node to follow 495 _followedNode:null, 496 // whether camera should be limited to certain area 497 _boundarySet:false, 498 // if screen size is bigger than the boundary - update not needed 499 _boundaryFullyCovered:false, 500 // fast access to the screen dimensions 501 _halfScreenSize:null, 502 _fullScreenSize:null, 503 _worldRect:null, 504 505 leftBoundary:0.0, 506 rightBoundary:0.0, 507 topBoundary:0.0, 508 bottomBoundary:0.0, 509 510 /** 511 * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. <br /> 512 * creates the action with a set boundary. <br/> 513 * creates the action with no boundary set. 514 * @param {cc.Node} followedNode 515 * @param {cc.Rect} rect 516 */ 517 ctor:function (followedNode, rect) { 518 cc.Action.prototype.ctor.call(this); 519 this._followedNode = null; 520 this._boundarySet = false; 521 522 this._boundaryFullyCovered = false; 523 this._halfScreenSize = null; 524 this._fullScreenSize = null; 525 526 this.leftBoundary = 0.0; 527 this.rightBoundary = 0.0; 528 this.topBoundary = 0.0; 529 this.bottomBoundary = 0.0; 530 this._worldRect = cc.rect(0, 0, 0, 0); 531 532 if(followedNode) 533 rect ? this.initWithTarget(followedNode, rect) 534 : this.initWithTarget(followedNode); 535 }, 536 537 /** 538 * to copy object with deep copy. 539 * returns a clone of action. 540 * 541 * @return {cc.Follow} 542 */ 543 clone:function () { 544 var action = new cc.Follow(); 545 var locRect = this._worldRect; 546 var rect = new cc.Rect(locRect.x, locRect.y, locRect.width, locRect.height); 547 action.initWithTarget(this._followedNode, rect); 548 return action; 549 }, 550 551 /** 552 * Get whether camera should be limited to certain area. 553 * 554 * @return {Boolean} 555 */ 556 isBoundarySet:function () { 557 return this._boundarySet; 558 }, 559 560 /** 561 * alter behavior - turn on/off boundary. 562 * 563 * @param {Boolean} value 564 */ 565 setBoudarySet:function (value) { 566 this._boundarySet = value; 567 }, 568 569 /** 570 * initializes the action with a set boundary. 571 * 572 * @param {cc.Node} followedNode 573 * @param {cc.Rect} [rect=] 574 * @return {Boolean} 575 */ 576 initWithTarget:function (followedNode, rect) { 577 if(!followedNode) 578 throw new Error("cc.Follow.initWithAction(): followedNode must be non nil"); 579 580 var _this = this; 581 rect = rect || cc.rect(0, 0, 0, 0); 582 _this._followedNode = followedNode; 583 _this._worldRect = rect; 584 585 _this._boundarySet = !cc._rectEqualToZero(rect); 586 587 _this._boundaryFullyCovered = false; 588 589 var winSize = cc.director.getWinSize(); 590 _this._fullScreenSize = cc.p(winSize.width, winSize.height); 591 _this._halfScreenSize = cc.pMult(_this._fullScreenSize, 0.5); 592 593 if (_this._boundarySet) { 594 _this.leftBoundary = -((rect.x + rect.width) - _this._fullScreenSize.x); 595 _this.rightBoundary = -rect.x; 596 _this.topBoundary = -rect.y; 597 _this.bottomBoundary = -((rect.y + rect.height) - _this._fullScreenSize.y); 598 599 if (_this.rightBoundary < _this.leftBoundary) { 600 // screen width is larger than world's boundary width 601 //set both in the middle of the world 602 _this.rightBoundary = _this.leftBoundary = (_this.leftBoundary + _this.rightBoundary) / 2; 603 } 604 if (_this.topBoundary < _this.bottomBoundary) { 605 // screen width is larger than world's boundary width 606 //set both in the middle of the world 607 _this.topBoundary = _this.bottomBoundary = (_this.topBoundary + _this.bottomBoundary) / 2; 608 } 609 610 if ((_this.topBoundary === _this.bottomBoundary) && (_this.leftBoundary === _this.rightBoundary)) 611 _this._boundaryFullyCovered = true; 612 } 613 return true; 614 }, 615 616 /** 617 * called every frame with it's delta time. <br /> 618 * DON'T override unless you know what you are doing. 619 * 620 * @param {Number} dt 621 */ 622 step:function (dt) { 623 var tempPosX = this._followedNode.x; 624 var tempPosY = this._followedNode.y; 625 tempPosX = this._halfScreenSize.x - tempPosX; 626 tempPosY = this._halfScreenSize.y - tempPosY; 627 628 //TODO Temporary treatment - The dirtyFlag symbol error 629 this.target._renderCmd._dirtyFlag = 0; 630 631 if (this._boundarySet) { 632 // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased 633 if (this._boundaryFullyCovered) 634 return; 635 636 this.target.setPosition(cc.clampf(tempPosX, this.leftBoundary, this.rightBoundary), cc.clampf(tempPosY, this.bottomBoundary, this.topBoundary)); 637 } else { 638 this.target.setPosition(tempPosX, tempPosY); 639 } 640 }, 641 642 /** 643 * Return true if the action has finished. 644 * 645 * @return {Boolean} 646 */ 647 isDone:function () { 648 return ( !this._followedNode.running ); 649 }, 650 651 /** 652 * Stop the action. 653 */ 654 stop:function () { 655 this.target = null; 656 cc.Action.prototype.stop.call(this); 657 } 658 }); 659 660 /** 661 * creates the action with a set boundary. <br/> 662 * creates the action with no boundary set. 663 * 664 * @function 665 * @param {cc.Node} followedNode 666 * @param {cc.Rect} rect 667 * @return {cc.Follow|Null} returns the cc.Follow object on success 668 * @example 669 * // example 670 * // creates the action with a set boundary 671 * var sprite = new cc.Sprite("spriteFileName"); 672 * var followAction = cc.follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); 673 * this.runAction(followAction); 674 * 675 * // creates the action with no boundary set 676 * var sprite = new cc.Sprite("spriteFileName"); 677 * var followAction = cc.follow(sprite); 678 * this.runAction(followAction); 679 */ 680 cc.follow = function (followedNode, rect) { 681 return new cc.Follow(followedNode, rect); 682 }; 683 684 /** 685 * Please use cc.follow instead. 686 * creates the action with a set boundary. <br/> 687 * creates the action with no boundary set. 688 * @param {cc.Node} followedNode 689 * @param {cc.Rect} rect 690 * @return {cc.Follow|Null} returns the cc.Follow object on success 691 * @static 692 * @deprecated since v3.0 please cc.follow() instead. 693 */ 694 cc.Follow.create = cc.follow; 695