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