1 /** 2 * The Render Engine 3 * Mover2DComponent 4 * 5 * @fileoverview An extension of the transform 2D component which adds physical 6 * movement properties such as mass, gravity, and velocity. 7 * 8 * @author: Brett Fattori (brettf@renderengine.com) 9 * @author: $Author: bfattori $ 10 * @version: $Revision: 1555 $ 11 * 12 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this software and associated documentation files (the "Software"), to deal 16 * in the Software without restriction, including without limitation the rights 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the Software is 19 * furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 * THE SOFTWARE. 31 * 32 */ 33 34 // The class this file defines and its required classes 35 R.Engine.define({ 36 "class":"R.components.transform.Mover2D", 37 "requires":[ 38 "R.components.Transform2D", 39 "R.engine.Events", 40 "R.lang.Timeout", 41 "R.math.Point2D", 42 "R.math.Vector2D" 43 ] 44 }); 45 46 /** 47 * @class A mover component that adds simplified physical transformations to an object. 48 * Properties include velocity, acceleration, mass, and gravity. 49 * 50 * @param name {String} The name of the component 51 * @param priority {Number} The priority of this component between 0.0 and 1.0 52 * @extends R.components.Transform2D 53 * @constructor 54 * @description Creates a 2d mover component 55 */ 56 R.components.transform.Mover2D = function () { 57 "use strict"; 58 return R.components.Transform2D.extend(/** @scope R.components.transform.Mover2D.prototype */{ 59 60 velocity:null, 61 _nVel:null, 62 vDecay:0, 63 angularVelocity:0, 64 lPos:null, 65 maxVelocity:0, 66 acceleration:null, 67 gravity:null, 68 mass:null, 69 atRest:null, 70 checkRest:null, 71 restingVelocity:null, 72 lagAdjustment:null, 73 checkLag:null, 74 _vec:null, 75 firstFrame:false, 76 77 /** 78 * @private 79 */ 80 constructor:function (name, priority) { 81 this.base(name, priority || 1.0); 82 this.velocity = R.math.Vector2D.create(0, 0); 83 this.angularVelocity = 0; 84 this._nVel = R.math.Vector2D.create(0, 0); 85 this.acceleration = R.math.Vector2D.create(0, 0); 86 this.lPos = R.math.Point2D.create(0, 0); 87 this.vDecay = 0; 88 this.maxVelocity = -1; 89 this.gravity = R.math.Vector2D.create(0, 0); 90 this.atRest = false; 91 this.checkRest = true; 92 this.mass = 1; 93 this.restingVelocity = R.components.transform.Mover2D.DEFAULT_RESTING_VELOCITY; 94 this.lagAdjustment = R.components.transform.Mover2D.DEFAULT_LAG_ADJUSTMENT; 95 this.checkLag = true; 96 this.firstFrame = true; 97 98 // Temp vector to use in calcs 99 this._vec = R.math.Vector2D.create(0, 0); 100 }, 101 102 /** 103 * Destroys the component instance 104 */ 105 destroy:function () { 106 this.velocity.destroy(); 107 this._nVel.destroy(); 108 this.acceleration.destroy(); 109 this.lPos.destroy(); 110 this.gravity.destroy(); 111 this._vec.destroy(); 112 this.base(); 113 }, 114 115 /** 116 * Releases the component back into the object pool. See {@link R.engine.PooledObject#release} 117 * for more information. 118 */ 119 release:function () { 120 this.base(); 121 this.velocity = null; 122 this._nVel = null; 123 this.vDecay = 0; 124 this.angularVelocity = 0; 125 this.lPos = null; 126 this.maxVelocity = -1; 127 this.acceleration = null; 128 this.gravity = null; 129 this.atRest = null; 130 this.checkRest = null; 131 this.mass = null; 132 this.restingVelocity = null; 133 this.lagAdjustment = null; 134 this.checkLag = null; 135 this._vec = null; 136 this.firstFrame = true; 137 }, 138 139 /** 140 * Updates the transformation of the component, setting the 141 * position and rotation based on the time that has elapsed since 142 * the last update. This component handles frame rate independent 143 * updates so that lag between frames doesn't affect the relative 144 * position or rotation. 145 * 146 * @param renderContext {R.rendercontexts.AbstractRenderContext} The render context for the component 147 * @param time {Number} The engine time in milliseconds 148 * @param dt {Number} The delta between the world time and the last time the world was updated 149 * in milliseconds. 150 */ 151 execute:function (renderContext, time, dt) { 152 if (!this.isResting()) { 153 this.lPos.set(this.getPosition()); 154 var rot = this.getRotation(); 155 156 // If we've just come into the world, we can short circuit with a 157 // quick addition of the velocity. 158 if (this.firstFrame) { 159 this.setPosition(this.lPos.add(this.velocity).add(this.acceleration).add(this.gravity)); 160 this.setRotation(rot); 161 } else { 162 if (this.getVelocityDecay() != 0 && this.velocity.len() > 0) { 163 // We need to decay the velocity by the amount 164 // specified until velocity is zero, or less than zero 165 this._vec.set(this.velocity).neg(); 166 this._vec.mul(this.getVelocityDecay()); 167 this.velocity.add(this._vec); 168 } 169 170 // Adjust the step value for lagging frame rates 171 this._vec.set(this.velocity.add(this.acceleration).add(this.gravity)); 172 this._vec.mul(dt / R.Engine.fpsClock); 173 174 if (this.maxVelocity != -1 && this._vec.len() > this.maxVelocity) { 175 this._vec.normalize().mul(this.maxVelocity); 176 } 177 178 this.setPosition(this.lPos.add(this._vec)); 179 180 // TODO: Actually implement angular velocity per time step 181 var angVel = this.angularVelocity * (dt / R.Engine.fpsClock); 182 this.setRotation(rot + angVel); 183 } 184 185 // Check rest state 186 if (this.getCheckRestState()) { 187 if (this.getVelocity().len() < this.getRestingVelocity()) { 188 this.setVelocity(R.math.Vector2D.ZERO); 189 this.atRest = true; 190 } 191 } 192 } 193 194 this.firstFrame = false; 195 this.base(renderContext, time, dt); 196 }, 197 198 /** 199 * Setting this to <tt>true</tt> will enable a check for time lag and adjust 200 * calculations by a specified factor. 201 * 202 * @param state {Boolean} <tt>true</tt> to check for lag 203 */ 204 setCheckLag:function (state) { 205 this.checkLag = state; 206 }, 207 208 /** 209 * Returns <tt>true</tt> if calculations should determine time lag and adjust. 210 * @return {Boolean} 211 */ 212 isCheckLag:function () { 213 return this.checkLag; 214 }, 215 216 /** 217 * Sets the value by which calculations will be adjusted for time lag. 218 * 219 * @param lagAdj {Number} The adjustment value 220 */ 221 setLagAdjustment:function (lagAdj) { 222 if (lagAdj != 0) { 223 this.lagAdjustment = lagAdj; 224 } 225 }, 226 227 /** 228 * Get the value by which calculations are adjusted for time lag. 229 * @return {Number} The adjustment value 230 */ 231 getLagAdjustment:function () { 232 return this.lagAdjustment; 233 }, 234 235 /** 236 * Set the velocity vector of the component. 237 * 238 * @param vector {Number|R.math.Vector2D} The velocity vector, or the X velocity 239 * @param [y] {Number} If <tt>vector</tt> is a number, this is the Y velocity 240 */ 241 setVelocity:function (vector, y) { 242 this.velocity.set(vector, y); 243 if (!this.velocity.isZero()) { 244 this.atRest = false; 245 } 246 }, 247 248 /** 249 * Returns the velocity vector of the component 250 * @return {R.math.Vector2D} 251 */ 252 getVelocity:function () { 253 return this.velocity; 254 }, 255 256 /** 257 * Returns <tt>true</tt> if the component is in a resting state. 258 * @return {Boolean} 259 */ 260 isResting:function () { 261 return this.atRest; 262 }, 263 264 /** 265 * Setting this to <tt>true</tt> will stop further movement calculations 266 * from occuring. Marks the object as being "at rest". 267 * 268 * @param state {Boolean} <tt>true</tt> to stop movement 269 */ 270 setResting:function (state) { 271 this.atRest = state; 272 }, 273 274 /** 275 * Get the magnitude at which velocity is determined to be close enough to 276 * zero to be "at rest". 277 * @return {Number} The resting velocity magnitude 278 */ 279 getRestingVelocity:function () { 280 return this.restingVelocity; 281 }, 282 283 /** 284 * Set the magnitude of velocity which determines if the object is "at rest". 285 * 286 * @param mag {Number} The velocity magnitude which is "at rest" 287 */ 288 setRestingVelocity:function (mag) { 289 this.restingVelocity = mag; 290 }, 291 292 /** 293 * If set to <tt>true</tt>, the component will check to see if the 294 * velocity magnitude has dropped below a defined rate. When the 295 * velocity magnitude drops below the set rate, the object will be 296 * marked as "at rest" and no calculations will be made until the 297 * object is set into motion again. 298 * 299 * @param state {Boolean} <tt>true</tt> to check to see if the velocity 300 * has reached a "resting state". 301 */ 302 setCheckRestState:function (state) { 303 this.checkRest = state; 304 if (this.isResting() && !state) { 305 this.setResting(false); 306 } 307 }, 308 309 /** 310 * Determine if the component should check to see if the velocity has 311 * dropped below a level which would indicate "at rest". 312 * @return {Boolean} <tt>true</tt> if the component will check for the "resting state" 313 */ 314 getCheckRestState:function () { 315 return this.checkRest; 316 }, 317 318 /** 319 * Set the acceleration vector. Acceleration will be constantly applied to 320 * the last position. 321 * 322 * @param vector {Number|R.math.Vector2D} The acceleration vector, or acceleration along X 323 * @param [y] {Number} If <tt>vector</tt> is a number, the acceleration along Y 324 */ 325 setAcceleration:function (vector, y) { 326 this.acceleration.set(vector, y); 327 this.atRest = false; 328 }, 329 330 /** 331 * Get the acceleration vector. 332 * @return {R.math.Vector2D} The acceleration vector 333 */ 334 getAcceleration:function () { 335 return this.acceleration; 336 }, 337 338 /** 339 * Set the vector of gravity. 340 * @param vector {Number|R.math.Vector2D} The gravity vector, or gravity along X 341 * @param [y] {Number} If <tt>vector</tt> is a number, the gravity along Y 342 */ 343 setGravity:function (vector, y) { 344 this.gravity.set(vector, y); 345 this.atRest = false; 346 }, 347 348 /** 349 * Get the gravity vector 350 * @return {R.math.Vector2D} The gravity vector 351 */ 352 getGravity:function () { 353 return this.gravity; 354 }, 355 356 /** 357 * Set the mass of the object which can be subsequently used in 358 * calculations like friction and energy transfer. 359 * 360 * @param mass {Number} The mass of the object 361 */ 362 setMass:function (mass) { 363 this.mass = mass; 364 }, 365 366 /** 367 * Get the mass of the object. 368 * @return {Number} The mass of the object 369 */ 370 getMass:function () { 371 return this.mass; 372 }, 373 374 /** 375 * Set the maximum velocity. Setting this value to <tt>zero</tt> indicates that 376 * there is no maximum velocity. 377 * @param maxVel {Number} The maximum velocity 378 */ 379 setMaxVelocity:function (maxVel) { 380 this.maxVelocity = maxVel; 381 }, 382 383 /** 384 * Get the maximum velocity. 385 * @return {Number} The maximum velocity 386 */ 387 getMaxVelocity:function () { 388 return this.maxVelocity; 389 }, 390 391 /** 392 * Set the decay rate at which the velocity will approach zero. 393 * You can use this value to cause a moving object to eventually 394 * stop moving. (e.g. friction) 395 * 396 * @param decay {Number} The rate at which velocity decays 397 */ 398 setVelocityDecay:function (decay) { 399 this.vDecay = decay; 400 }, 401 402 /** 403 * Get the rate at which velocity will decay to zero. 404 * @return {Number} The velocity decay rate 405 */ 406 getVelocityDecay:function () { 407 return this.vDecay; 408 }, 409 410 /** 411 * Set the angular velocity. 412 * @param angularVelocity {Number} The angle of change 413 */ 414 setAngularVelocity:function (angularVelocity) { 415 this.angularVelocity = angularVelocity; 416 }, 417 418 /** 419 * Returns the angular velocity. 420 * @return {Number} 421 */ 422 getAngularVelocity:function () { 423 return this.angularVelocity; 424 } 425 }, /** @scope R.components.transform.Mover2D.prototype */{ 426 /** 427 * Get the class name of this object 428 * @return {String} "R.components.transform.Mover2D" 429 */ 430 getClassName:function () { 431 return "R.components.transform.Mover2D"; 432 }, 433 434 /** 435 * The default velocity magnitude considered to be "at rest" 436 * @type {Number} 437 */ 438 DEFAULT_RESTING_VELOCITY:0.2, 439 440 /** 441 * The default adjustment made to calculations when a lag occurs between the last time 442 * the component was updated and the current time. 443 * @type {Number} 444 */ 445 DEFAULT_LAG_ADJUSTMENT:0.01 446 }); 447 };