CCAction.js 15 KB

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