CCActionCatmullRom.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /****************************************************************************
  2. Copyright (c) 2010-2012 cocos2d-x.org
  3. Copyright (c) 2008-2010 Ricardo Quesada
  4. Copyright (c) 2011 Zynga Inc.
  5. Copyright (c) 2008 Radu Gruian
  6. Copyright (c) 2011 Vit Valentin
  7. http://www.cocos2d-x.org
  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. The above copyright notice and this permission notice shall be included in
  15. all copies or substantial portions of the Software.
  16. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. THE SOFTWARE.
  23. Orignal code by Radu Gruian: http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio.So
  24. Adapted to cocos2d-x by Vit Valentin
  25. Adapted from cocos2d-x to cocos2d-iphone by Ricardo Quesada
  26. ****************************************************************************/
  27. /**
  28. * <p>Returns the Cardinal Spline position for a given set of control points, tension and time CatmullRom Spline formula: <br/>
  29. * s(-ttt + 2tt - t)P1 + s(-ttt + tt)P2 + (2ttt - 3tt + 1)P2 + s(ttt - 2tt + t)P3 + (-2ttt + 3tt)P3 + s(ttt - tt)P4
  30. * </p>
  31. * @function
  32. * @param {cc.Point} p0
  33. * @param {cc.Point} p1
  34. * @param {cc.Point} p2
  35. * @param {cc.Point} p3
  36. * @param {Number} tension
  37. * @param {Number} t
  38. * @return {cc.Point}
  39. */
  40. cc.CardinalSplineAt = function (p0, p1, p2, p3, tension, t) {
  41. var t2 = t * t;
  42. var t3 = t2 * t;
  43. /*
  44. * Formula: s(-ttt + 2tt - t)P1 + s(-ttt + tt)P2 + (2ttt - 3tt + 1)P2 + s(ttt - 2tt + t)P3 + (-2ttt + 3tt)P3 + s(ttt - tt)P4
  45. */
  46. var s = (1 - tension) / 2;
  47. var b1 = s * ((-t3 + (2 * t2)) - t); // s(-t3 + 2 t2 - t)P1
  48. var b2 = s * (-t3 + t2) + (2 * t3 - 3 * t2 + 1); // s(-t3 + t2)P2 + (2 t3 - 3 t2 + 1)P2
  49. var b3 = s * (t3 - 2 * t2 + t) + (-2 * t3 + 3 * t2); // s(t3 - 2 t2 + t)P3 + (-2 t3 + 3 t2)P3
  50. var b4 = s * (t3 - t2); // s(t3 - t2)P4
  51. var x = (p0.x * b1 + p1.x * b2 + p2.x * b3 + p3.x * b4);
  52. var y = (p0.y * b1 + p1.y * b2 + p2.y * b3 + p3.y * b4);
  53. return cc.p(x, y);
  54. };
  55. /**
  56. * returns a new copy of the array reversed.
  57. * @return {Array}
  58. */
  59. cc.reverseControlPoints = function (controlPoints) {
  60. var newArray = [];
  61. for (var i = controlPoints.length - 1; i >= 0; i--) {
  62. newArray.push(cc.p(controlPoints[i].x, controlPoints[i].y));
  63. }
  64. return newArray;
  65. };
  66. cc.copyControlPoints = function (controlPoints) {
  67. var newArray = [];
  68. for (var i = 0; i < controlPoints.length; i++)
  69. newArray.push(cc.p(controlPoints[i].x, controlPoints[i].y));
  70. return newArray;
  71. };
  72. /**
  73. * returns a point from the array
  74. * @param {Array} controlPoints
  75. * @param {Number} pos
  76. * @return {Array}
  77. */
  78. cc.getControlPointAt = function (controlPoints, pos) {
  79. var p = Math.min(controlPoints.length - 1, Math.max(pos, 0));
  80. return controlPoints[p];
  81. };
  82. /**
  83. * reverse the current control point array inline, without generating a new one
  84. */
  85. cc.reverseControlPointsInline = function (controlPoints) {
  86. var len = controlPoints.length;
  87. var mid = 0 | (len / 2);
  88. for (var i = 0; i < mid; ++i) {
  89. var temp = controlPoints[i];
  90. controlPoints[i] = controlPoints[len - i - 1];
  91. controlPoints[len - i - 1] = temp;
  92. }
  93. };
  94. /**
  95. * Cardinal Spline path. http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline
  96. * @class
  97. * @extends cc.ActionInterval
  98. *
  99. * @example
  100. * //create a cc.CardinalSplineTo
  101. * var action1 = cc.CardinalSplineTo.create(3, array, 0);
  102. */
  103. cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# */{
  104. /** Array of control points */
  105. _points:null,
  106. _deltaT:0,
  107. _tension:0,
  108. _previousPosition:null,
  109. _accumulatedDiff:null,
  110. /**
  111. * Constructor
  112. */
  113. ctor:function () {
  114. cc.ActionInterval.prototype.ctor.call(this);
  115. this._points = [];
  116. this._deltaT = 0;
  117. this._tension = 0;
  118. this._previousPosition = null;
  119. this._accumulatedDiff = null;
  120. },
  121. /**
  122. * initializes the action with a duration and an array of points
  123. * @param {Number} duration
  124. * @param {Array} points array of control points
  125. * @param {Number} tension
  126. * @return {Boolean}
  127. */
  128. initWithDuration:function (duration, points, tension) {
  129. if(!points || points.length == 0)
  130. throw "Invalid configuration. It must at least have one control point";
  131. if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) {
  132. this.setPoints(points);
  133. this._tension = tension;
  134. return true;
  135. }
  136. return false;
  137. },
  138. /**
  139. * returns a new clone of the action
  140. * @returns {cc.CardinalSplineTo}
  141. */
  142. clone:function () {
  143. var action = new cc.CardinalSplineTo();
  144. action.initWithDuration(this._duration, cc.copyControlPoints(this._points), this._tension);
  145. return action;
  146. },
  147. /**
  148. * @param {cc.Node} target
  149. */
  150. startWithTarget:function (target) {
  151. cc.ActionInterval.prototype.startWithTarget.call(this, target);
  152. // Issue #1441 from cocos2d-iphone
  153. this._deltaT = 1 / (this._points.length - 1);
  154. var locPosition = this._target.getPosition();
  155. this._previousPosition = cc.p(locPosition.x, locPosition.y);
  156. this._accumulatedDiff = cc.p(0, 0);
  157. },
  158. /**
  159. * @param {Number} time
  160. */
  161. update:function (time) {
  162. var p, lt;
  163. var ps = this._points;
  164. // eg.
  165. // p..p..p..p..p..p..p
  166. // 1..2..3..4..5..6..7
  167. // want p to be 1, 2, 3, 4, 5, 6
  168. if (time == 1) {
  169. p = ps.length - 1;
  170. lt = 1;
  171. } else {
  172. var locDT = this._deltaT;
  173. p = 0 | (time / locDT);
  174. lt = (time - locDT * p) / locDT;
  175. }
  176. var newPos = cc.CardinalSplineAt(
  177. cc.getControlPointAt(ps, p - 1),
  178. cc.getControlPointAt(ps, p - 0),
  179. cc.getControlPointAt(ps, p + 1),
  180. cc.getControlPointAt(ps, p + 2),
  181. this._tension, lt);
  182. if (cc.ENABLE_STACKABLE_ACTIONS) {
  183. var tempX, tempY;
  184. tempX = this._target.getPositionX() - this._previousPosition.x;
  185. tempY = this._target.getPositionY() - this._previousPosition.y;
  186. if (tempX != 0 || tempY != 0) {
  187. var locAccDiff = this._accumulatedDiff;
  188. tempX = locAccDiff.x + tempX;
  189. tempY = locAccDiff.y + tempY;
  190. locAccDiff.x = tempX;
  191. locAccDiff.y = tempY;
  192. newPos.x += tempX;
  193. newPos.y += tempY;
  194. }
  195. }
  196. this.updatePosition(newPos);
  197. },
  198. /**
  199. * reverse a new cc.CardinalSplineTo
  200. * @return {cc.CardinalSplineTo}
  201. */
  202. reverse:function () {
  203. var reversePoints = cc.reverseControlPoints(this._points);
  204. return cc.CardinalSplineTo.create(this._duration, reversePoints, this._tension);
  205. },
  206. /**
  207. * update position of target
  208. * @param {cc.Point} newPos
  209. */
  210. updatePosition:function (newPos) {
  211. this._target.setPosition(newPos);
  212. this._previousPosition = newPos;
  213. },
  214. /**
  215. * Points getter
  216. * @return {Array}
  217. */
  218. getPoints:function () {
  219. return this._points;
  220. },
  221. /**
  222. * Points setter
  223. * @param {Array} points
  224. */
  225. setPoints:function (points) {
  226. this._points = points;
  227. }
  228. });
  229. /**
  230. * creates an action with a Cardinal Spline array of points and tension
  231. * @function
  232. * @param {Number} duration
  233. * @param {Array} points array of control points
  234. * @param {Number} tension
  235. * @return {cc.CardinalSplineTo}
  236. *
  237. * @example
  238. * //create a cc.CardinalSplineTo
  239. * var action1 = cc.CardinalSplineTo.create(3, array, 0);
  240. */
  241. cc.CardinalSplineTo.create = function (duration, points, tension) {
  242. var ret = new cc.CardinalSplineTo();
  243. if (ret.initWithDuration(duration, points, tension)) {
  244. return ret;
  245. }
  246. return null;
  247. };
  248. /**
  249. * Cardinal Spline path. http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline
  250. * @class
  251. * @extends cc.CardinalSplineTo
  252. *
  253. * @example
  254. * //create a cc.CardinalSplineBy
  255. * var action1 = cc.CardinalSplineBy.create(3, array, 0);
  256. */
  257. cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# */{
  258. _startPosition:null,
  259. /**
  260. * Constructor
  261. */
  262. ctor:function () {
  263. cc.CardinalSplineTo.prototype.ctor.call(this);
  264. this._startPosition = cc.p(0, 0);
  265. },
  266. /**
  267. * @param {cc.Node} target
  268. */
  269. startWithTarget:function (target) {
  270. cc.CardinalSplineTo.prototype.startWithTarget.call(this, target);
  271. var locPosition = target.getPosition();
  272. this._startPosition.x = locPosition.x;
  273. this._startPosition.y = locPosition.y;
  274. },
  275. /**
  276. * reverse a new cc.CardinalSplineBy
  277. * @return {cc.CardinalSplineBy}
  278. */
  279. reverse:function () {
  280. var copyConfig = this._points.slice();
  281. var current;
  282. //
  283. // convert "absolutes" to "diffs"
  284. //
  285. var p = copyConfig[0];
  286. for (var i = 1; i < copyConfig.length; ++i) {
  287. current = copyConfig[i];
  288. copyConfig[i] = cc.pSub(current, p);
  289. p = current;
  290. }
  291. // convert to "diffs" to "reverse absolute"
  292. var reverseArray = cc.reverseControlPoints(copyConfig);
  293. // 1st element (which should be 0,0) should be here too
  294. p = reverseArray[ reverseArray.length - 1 ];
  295. reverseArray.pop();
  296. p.x = -p.x;
  297. p.y = -p.y;
  298. reverseArray.unshift(p);
  299. for (var i = 1; i < reverseArray.length; ++i) {
  300. current = reverseArray[i];
  301. current.x = -current.x;
  302. current.y = -current.y;
  303. current.x += p.x;
  304. current.y += p.y;
  305. reverseArray[i] = current;
  306. p = current;
  307. }
  308. return cc.CardinalSplineBy.create(this._duration, reverseArray, this._tension);
  309. },
  310. /**
  311. * update position of target
  312. * @param {cc.Point} newPos
  313. */
  314. updatePosition:function (newPos) {
  315. var pos = this._startPosition;
  316. var posX = newPos.x + pos.x;
  317. var posY = newPos.y + pos.y;
  318. this._target.setPosition(posX, posY);
  319. this._previousPosition.x = posX;
  320. this._previousPosition.y = posY;
  321. },
  322. /**
  323. * returns a new clone of the action
  324. * @returns {cc.CardinalSplineBy}
  325. */
  326. clone:function () {
  327. var a = new cc.CardinalSplineBy();
  328. a.initWithDuration(this._duration, cc.copyControlPoints(this._points), this._tension);
  329. return a;
  330. }
  331. });
  332. /**
  333. * creates an action with a Cardinal Spline array of points and tension
  334. * @function
  335. * @param {Number} duration
  336. * @param {Array} points
  337. * @param {Number} tension
  338. * @return {cc.CardinalSplineBy}
  339. */
  340. cc.CardinalSplineBy.create = function (duration, points, tension) {
  341. var ret = new cc.CardinalSplineBy();
  342. if (ret.initWithDuration(duration, points, tension))
  343. return ret;
  344. return null;
  345. };
  346. /**
  347. * <p>
  348. * An action that moves the target with a CatmullRom curve to a destination point.<br/>
  349. * A Catmull Rom is a Cardinal Spline with a tension of 0.5. <br/>
  350. * http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline
  351. * </p>
  352. * @class
  353. * @extends cc.CardinalSplineTo
  354. *
  355. * @example
  356. * var action1 = cc.CatmullRomTo.create(3, array);
  357. */
  358. cc.CatmullRomTo = cc.CardinalSplineTo.extend(/** @lends cc.CatmullRomTo# */{
  359. /**
  360. * initializes the action with a duration and an array of points
  361. */
  362. initWithDuration:function (dt, points) {
  363. return cc.CardinalSplineTo.prototype.initWithDuration.call(this, dt, points, 0.5);
  364. },
  365. /**
  366. * returns a new clone of the action
  367. * @returns {cc.CatmullRomTo}
  368. */
  369. clone:function () {
  370. var action = new cc.CatmullRomTo();
  371. action.initWithDuration(this._duration, cc.copyControlPoints(this._points));
  372. return action;
  373. }
  374. });
  375. /**
  376. * creates an action with a Cardinal Spline array of points and tension
  377. * @param {Number} dt
  378. * @param {Array} points
  379. * @return {cc.CatmullRomTo}
  380. *
  381. * @example
  382. * var action1 = cc.CatmullRomTo.create(3, array);
  383. */
  384. cc.CatmullRomTo.create = function (dt, points) {
  385. var ret = new cc.CatmullRomTo();
  386. if (ret.initWithDuration(dt, points))
  387. return ret;
  388. return null;
  389. };
  390. /**
  391. * <p>
  392. * An action that moves the target with a CatmullRom curve by a certain distance. <br/>
  393. * A Catmull Rom is a Cardinal Spline with a tension of 0.5.<br/>
  394. * http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline
  395. * </p>
  396. * @class
  397. * @extends cc.CardinalSplineBy
  398. *
  399. * @example
  400. * var action1 = cc.CatmullRomBy.create(3, array);
  401. */
  402. cc.CatmullRomBy = cc.CardinalSplineBy.extend({
  403. /** initializes the action with a duration and an array of points */
  404. initWithDuration:function (dt, points) {
  405. return cc.CardinalSplineTo.prototype.initWithDuration.call(this, dt, points, 0.5);
  406. },
  407. /**
  408. * returns a new clone of the action
  409. * @returns {cc.CatmullRomBy}
  410. */
  411. clone:function () {
  412. var action = new cc.CatmullRomBy();
  413. action.initWithDuration(this._duration, cc.copyControlPoints(this._points));
  414. return action;
  415. }
  416. });
  417. /**
  418. * creates an action with a Cardinal Spline array of points and tension
  419. *
  420. * @example
  421. * var action1 = cc.CatmullRomBy.create(3, array);
  422. */
  423. cc.CatmullRomBy.create = function (dt, points) {
  424. var ret = new cc.CatmullRomBy();
  425. if (ret.initWithDuration(dt, points))
  426. return ret;
  427. return null;
  428. };