1 /** 2 * Copyright (C) 2009-2011 Klaus Reimer <k@ailis.de> 3 * See LICENSE.txt for licensing information. 4 * 5 * @require twodee.js 6 */ 7 8 /** 9 * Constructs a new physics model. 10 * 11 * @constructor 12 * @class 13 * A physics model. 14 */ 15 twodee.Physics = function() 16 { 17 this.velocity = new twodee.Vector(); 18 this.acceleration = new twodee.Vector(); 19 twodee.Physics.counter++; 20 }; 21 22 /** 23 * Instance counter. 24 * 25 * @type {number} 26 */ 27 twodee.Physics.counter = 0; 28 29 /** 30 * A static temporary vector for speed optimization. 31 * 32 * @private 33 * @type {twodee.Vector} 34 */ 35 twodee.Physics.V = new twodee.Vector(); 36 37 /** 38 * The velocity vector. Length is units per second. 39 * 40 * @private 41 * @type {twodee.Vector} 42 */ 43 twodee.Physics.prototype.velocity = null; 44 45 /** 46 * The minimum velocity in units per second. 47 * 48 * @private 49 * @type {number} 50 */ 51 twodee.Physics.prototype.minVelocity = Number.NEGATIVE_INFINITY; 52 53 /** 54 * The maximum velocity in units per second. 55 * 56 * @private 57 * @type {number} 58 */ 59 twodee.Physics.prototype.maxVelocity = Number.POSITIVE_INFINITY; 60 61 /** 62 * The acceleration vector.Length is units per square second. 63 * 64 * @private 65 * @type {twodee.Vector} 66 */ 67 twodee.Physics.prototype.acceleration = null; 68 69 /** 70 * The spin in anti-clockwise RAD per second. 71 * 72 * @private 73 * @type {number} 74 */ 75 twodee.Physics.prototype.spin = 0; 76 77 /** 78 * The spin acceleration in anti-clockwise RAD per square second. 79 * 80 * @private 81 * @type {number} 82 */ 83 twodee.Physics.prototype.spinAcceleration = 0; 84 85 /** 86 * The minimum spin acceleration. 87 * 88 * @private 89 * @type {number} 90 */ 91 twodee.Physics.prototype.minSpin = Number.NEGATIVE_INFINITY; 92 93 /** 94 * The maximum spin acceleration. 95 * 96 * @private 97 * @type {number} 98 */ 99 twodee.Physics.prototype.maxSpin = Number.POSITIVE_INFINITY; 100 101 /** 102 * The scaling in multitudes per second. 103 * 104 * @private 105 * @type {number} 106 */ 107 twodee.Physics.prototype.scaling = 1; 108 109 /** 110 * The lifetime in seconds. 111 * 112 * @private 113 * @type {number} 114 */ 115 twodee.Physics.prototype.lifetime = Number.POSITIVE_INFINITY; 116 117 /** 118 * The decay time in seconds. 119 * 120 * @private 121 * @type {number} 122 */ 123 twodee.Physics.prototype.decay = 1; 124 125 /** 126 * Returns the velocity vector. The length is units per second. There is no setter 127 * because you should modify the returned vector instead. 128 * 129 * @return {twodee.Vector} The velocity vector. Never null 130 */ 131 twodee.Physics.prototype.getVelocity = function() 132 { 133 return this.velocity; 134 }; 135 136 /** 137 * Sets the minimum velocity in units per second. 138 * 139 * @param {number} minVelocity 140 * The minimum velocity to set 141 * @return {twodee.Physics} 142 * This physics instance for method chaining. 143 */ 144 twodee.Physics.prototype.setMinVelocity = function(minVelocity) 145 { 146 this.minVelocity = minVelocity; 147 return this; 148 }; 149 150 /** 151 * Returns the minimum velocity in units per second. 152 * 153 * @return {number} The minimum velocity 154 */ 155 twodee.Physics.prototype.getMinVelocity = function() 156 { 157 return this.minVelocity; 158 }; 159 160 /** 161 * Sets the maximum velocity in units per second. 162 * 163 * @param {number} maxVelocity 164 * The maximum velocity to set 165 * @return {twodee.Physics} 166 * This physics instance for method chaining. 167 */ 168 twodee.Physics.prototype.setMaxVelocity = function(maxVelocity) 169 { 170 this.maxVelocity = maxVelocity; 171 return this; 172 }; 173 174 /** 175 * Returns the maximum velocity in units per second. 176 * 177 * @return {number} The maximum velocity 178 */ 179 twodee.Physics.prototype.getMaxVelocity = function() 180 { 181 return this.maxVelocity; 182 }; 183 184 /** 185 * Returns the acceleration vector. The length is units per square second. 186 * There is no setter because you should modify the returned vector instead. 187 * 188 * @return {twodee.Vector} The acceleration vector. Never null 189 */ 190 twodee.Physics.prototype.getAcceleration= function() 191 { 192 return this.acceleration; 193 }; 194 195 /** 196 * Returns the spin in anti-clockwise RAD per second. 197 * 198 * @return {number} The current spin 199 */ 200 twodee.Physics.prototype.getSpin = function() 201 { 202 return this.spin; 203 }; 204 205 /** 206 * Sets the spin in anti-clockwise RAD per second. 207 * 208 * @param {number} spin 209 * The spin to set 210 * @return {twodee.Physics} 211 * This physics instance for method chaining. 212 */ 213 twodee.Physics.prototype.setSpin = function(spin) 214 { 215 this.spin = spin; 216 return this; 217 }; 218 219 /** 220 * Returns the spin acceleration in anti-clockwise RAD per square second. 221 * 222 * @return {number} The current spin acceleration 223 */ 224 twodee.Physics.prototype.getSpinAcceleration = function() 225 { 226 return this.spinAcceleration; 227 }; 228 229 /** 230 * Sets the spin acceleration in anti-clockwise RAD per square second. 231 * 232 * @param {number} spinAcceleration 233 * The spin acceleration to set 234 * @return {twodee.Physics} 235 * This physics instance for method chaining. 236 */ 237 twodee.Physics.prototype.setSpinAcceleration = function(spinAcceleration) 238 { 239 this.spinAcceleration = spinAcceleration; 240 return this; 241 }; 242 243 /** 244 * Returns the minimum spin in anti-clockwise RAD per second. 245 * 246 * @return {number} The minimum spin 247 */ 248 twodee.Physics.prototype.getMinSpin = function() 249 { 250 return this.minSpin; 251 }; 252 253 /** 254 * Sets the minimum spin in anti-clockwise RAD per second. 255 * 256 * @param {number} minSpin 257 * The minimum spin to set 258 * @return {twodee.Physics} 259 * This physics instance for method chaining. 260 */ 261 twodee.Physics.prototype.setMinSpin = function(minSpin) 262 { 263 this.minSpin = minSpin; 264 return this; 265 }; 266 267 /** 268 * Returns the maximum spin in anti-clockwise RAD per second. 269 * 270 * @return {number} The maximum spin 271 */ 272 twodee.Physics.prototype.getMaxSpin = function() 273 { 274 return this.maxSpin; 275 }; 276 277 /** 278 * Sets the maximum spin in anti-clockwise RAD per second. 279 * 280 * @param {number} maxSpin 281 * The maximum spin to set 282 * @return {twodee.Physics} 283 * This physics instance for method chaining. 284 */ 285 twodee.Physics.prototype.setMaxSpin = function(maxSpin) 286 { 287 this.maxSpin = maxSpin; 288 return this; 289 }; 290 291 /** 292 * Returns the scaling in multitudes per second. 293 * 294 * @return {number} The current scaling 295 */ 296 twodee.Physics.prototype.getScaling = function() 297 { 298 return this.scaling; 299 }; 300 301 /** 302 * Sets the scaling in multitudes per second. 303 * 304 * @param {number} scaling 305 * The scaling to set 306 * @return {twodee.Physics} 307 * This physics instance for method chaining. 308 */ 309 twodee.Physics.prototype.setScaling = function(scaling) 310 { 311 this.scaling = scaling; 312 return this; 313 }; 314 315 /** 316 * Returns the lifetime in seconds. May return Infinity. 317 * 318 * @return {number} The lifetime 319 */ 320 twodee.Physics.prototype.getLifetime = function() 321 { 322 return this.lifetime; 323 }; 324 325 /** 326 * Sets the lifetime in seconds. Default value is Infinity. 327 * 328 * @param {number} lifetime 329 * The lifetime to set 330 * @return {twodee.Physics} 331 * This physics instance for method chaining. 332 */ 333 twodee.Physics.prototype.setLifetime = function(lifetime) 334 { 335 this.lifetime = lifetime; 336 return this; 337 }; 338 339 /** 340 * Sets the decay time in seconds. Default value is 1 second. Decay only 341 * makes sense when a life time has been set. Example: Set lifetime to 10 342 * seconds and decay to 2 seconds. The scene node will start fading away 343 * (Decreasing the opacity) at 8 seconds and will be invisible and then 344 * removed at 10 seconds. 345 * 346 * @param {number} decay 347 * The decay time in seconds 348 * @return {twodee.Physics} 349 * This physics instance for method chaining. 350 */ 351 twodee.Physics.prototype.setDecay = function(decay) 352 { 353 this.decay = decay; 354 return this; 355 }; 356 357 /** 358 * Returns the decay time in seconds. 359 * 360 * @return {number} The decay time in seconds 361 */ 362 twodee.Physics.prototype.getDecay = function() 363 { 364 return this.decay; 365 }; 366 367 /** 368 * Processes the physics model for the specified node and time delta. 369 * 370 * @param {twodee.SceneNode} node 371 * The scene node to update 372 * @param {number} delta 373 * The time delta 374 */ 375 twodee.Physics.prototype.process = function(node, delta) 376 { 377 var spin, transform, velocity, factor, angle, v, acceleration, 378 spinAcceleration, curVelocity, maxVelocity, minVelocity, lifetime, 379 decay, scaling; 380 381 factor = delta / 1000; 382 383 // Process the lifetime 384 this.lifetime = lifetime = Math.max(0, this.lifetime - factor); 385 if (!lifetime) 386 { 387 node.remove(); 388 return; 389 } 390 391 // Process the decay 392 decay = this.decay; 393 if (decay > lifetime) node.setOpacity(lifetime / decay); 394 395 // Get the current node transform and a temporary vector 396 transform = node.getTransform(); 397 v = twodee.Physics.V; 398 399 // Process the velocity 400 velocity = this.velocity; 401 if (!velocity.isZero()) 402 { 403 angle = transform.getRotationAngle(); 404 velocity.copy(v).rotate(-angle); 405 transform.translate(v.x * factor, v.y * factor); 406 } 407 408 // Process the acceleration 409 acceleration = this.acceleration; 410 if (!acceleration.isZero()) 411 { 412 velocity.add(acceleration.copy(v).scale(factor)); 413 curVelocity = velocity.getLength(); 414 maxVelocity = this.maxVelocity; 415 minVelocity = this.minVelocity; 416 if (curVelocity > maxVelocity) 417 velocity.scale(maxVelocity / curVelocity); 418 else if (curVelocity < minVelocity) 419 velocity.scale(minVelocity / curVelocity); 420 } 421 422 // Process the spinning 423 spin = this.spin; 424 if (spin) transform.rotate(spin * factor); 425 426 // Process the scaling 427 scaling = this.scaling; 428 if (scaling != 1) transform.scale(Math.pow(scaling, factor)); 429 430 // Process the spin acceleration 431 spinAcceleration = this.spinAcceleration; 432 if (spinAcceleration) 433 this.spin = Math.max(this.minSpin, Math.min(this.maxSpin, spin + 434 spinAcceleration * factor)); 435 }; 436