1 /** 2 * @fileOverview 3 * physics.gl.enchant.js 4 * @version 0.3.6 5 * @require enchant.js v0.4.5+ 6 * @require gl.enchant.js v0.3.6+ 7 * @require primitive.gl.enchant.js v0.3.5+ 8 * @require gl-matrix.js 1.3.7+ 9 * @author UEI Corporation 10 * 11 * @description 12 * Physical calculation library using ammo.js 13 * Allows object movement using the gl.enchant.js physical calculator. 14 * @detail 15 * ammo.js: 16 * https://github.com/kripken/ammo.js 17 */ 18 if (typeof Ammo === 'undefined') { 19 throw new Error('physics.gl.enchant.js must be loaded after ammo.js'); 20 } 21 if (enchant.gl !== undefined && enchant.gl.primitive !== undefined) { 22 (function() { 23 /** 24 * namespace object 25 * @type {Object} 26 */ 27 enchant.gl.physics = {}; 28 /** 29 * @scope enchant.gl.physics.World.prototype 30 */ 31 enchant.gl.physics.World = enchant.Class.create({ 32 /** 33 * World in which physical calculator is used. 34 * Here we add a rigid object, and by proceeding forward in time physical calculation will be processed. 35 * @see enchant.gl.physics.PhyScene3D 36 * @constructs 37 */ 38 initialize: function() { 39 var g = new Ammo.btVector3(0, -10, 0); 40 var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration(); 41 var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration); 42 var pairCache = new Ammo.btDbvtBroadphase(); 43 var constraintSolver = new Ammo.btSequentialImpulseConstraintSolver(); 44 45 this._dynamicsWorld = new Ammo.btDiscreteDynamicsWorld( 46 dispatcher, pairCache, constraintSolver, collisionConfiguration); 47 48 this._dynamicsWorld.setGravity(g); 49 50 Ammo.destroy(g); 51 }, 52 /** 53 * Set gravity of World. 54 * @param {Number} gx x axis gravity. 55 * @param {Number} gy y axis gravity. 56 * @param {Number} gz z axis gravity. 57 */ 58 setGravity: function(gx, gy, gz) { 59 var g = new Ammo.btVector3(gx, gy, gz); 60 this._dynamicsWorld.setGravity(g); 61 Ammo.destroy(g); 62 }, 63 /** 64 * Continue World time. 65 * When timeStep is bigger than fixedTimeStep, you continue the number of times set in maxSubStep and continue with time. 66 * @param {Number} Amount of time you wish to proceed. Units are in seconds. 67 * @param {Number} maxSubSteps Maximum number of repetitions to be added to simulation. 68 * @param {Number} fixedTimeStep Standard time. The default level is 1/60. 69 * @return {Number} subStepsNum 70 */ 71 stepSimulation: function(timeStep, maxSubSteps, fixedTimeStep) { 72 return this._dynamicsWorld.stepSimulation(timeStep, maxSubSteps, fixedTimeStep); 73 }, 74 /** 75 * Add rigid body to World. 76 * @param {enchant.gl.physics.Rigid} Rigid Rigid body object to be added. 77 */ 78 addRigid: function(rigid) { 79 this._dynamicsWorld.addRigidBody(rigid.rigidBody); 80 rigid.world = this; 81 }, 82 /** 83 * Delete rigid body form world. 84 * @param {enchant.gl.physics.Rigid} Rigid Rigid body to be deleted. 85 */ 86 removeRigid: function(rigid) { 87 this._dynamicsWorld.removeRigidBody(rigid.rigidBody); 88 rigid.world = null; 89 }, 90 /** 91 * Judges whether or not two rigid objects have collided. 92 * @param {enchant.gl.physics.Rigid} rigid1 Rigid1 to be judged. 93 * @param {enchant.gl.physics.Rigid} rigid2 Rigid2 to be judged. 94 * @return {Boolean} bool Collison presence or absence. 95 */ 96 contactPairTest: function(rigid1, rigid2) { 97 var callback = new Ammo.ConcreteContactResultCallback(); 98 var result = false; 99 Ammo.customizeVTable(callback, [ 100 { 101 original: Ammo.ConcreteContactResultCallback.prototype.addSingleResult, 102 replacement: function(tp, cp, colObj0, partid0, index0, colObj1, partid1, index1) { 103 result = true; 104 } 105 } 106 ]); 107 this._dynamicsWorld.contactPairTest(rigid1.rigidBody, rigid2.rigidBody, callback); 108 Ammo.destroy(callback); 109 return result; 110 } 111 }); 112 113 /** 114 * @scope enchant.gl.physics.Rigid.prototype 115 */ 116 enchant.gl.physics.Rigid = enchant.Class.create({ 117 /** 118 * Rigid body object. 119 * Add to World and activate. 120 * @param shape Ammo.btCollisionShape object. 121 * @param {Number} mass Mass of rigid object. 122 * @param {Number} linearDamping Rate of decay of speed on straight line speed of rigid object. 123 * @param {Number} angularDamping Rate of decay of angled speed of rigid object. 124 * @see enchant.gl.physics.RigidBox 125 * @see enchant.gl.physics.RigidCube 126 * @see enchant.gl.physics.RigidSphere 127 * @see enchant.gl.physics.RigidCylinder 128 * @see enchant.gl.physics.RigidCapsule 129 * @see enchant.gl.physics.RigidPlane 130 * @see enchant.gl.physics.RigidContainer 131 * @constructs 132 */ 133 initialize: function(shape, mass, lDamp, aDamp) { 134 if (typeof shape === 'undefined') { 135 shape = new Ammo.btBoxShape(1); 136 } 137 if (typeof mass === 'undefined') { 138 mass = 1; 139 } 140 141 var localInertia = new Ammo.btVector3(0, 0, 0); 142 shape.calculateLocalInertia(mass, localInertia); 143 144 var transform = new Ammo.btTransform(); 145 transform.setIdentity(); 146 147 var motionState = new Ammo.btDefaultMotionState(transform); 148 var rigidBodyInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia); 149 rigidBodyInfo.set_m_restitution(0.1); 150 rigidBodyInfo.set_m_friction(3.0); 151 152 if (typeof lDamp !== 'undefined') { 153 rigidBodyInfo.set_m_linearDamping(lDamp); 154 } 155 if (typeof aDamp !== 'undefined') { 156 rigidBodyInfo.set_m_angularDamping(aDamp); 157 } 158 159 this.shape = shape; 160 /** 161 * World that Rigid belongs to 162 */ 163 this.world = null; 164 165 /** 166 * Ammo rigid body object 167 */ 168 this.rigidBody = new Ammo.btRigidBody(rigidBodyInfo); 169 var p = Ammo.getPointer(this.rigidBody); 170 enchant.gl.physics.Rigid._refs[p] = this; 171 172 Ammo.destroy(transform); 173 Ammo.destroy(localInertia); 174 Ammo.destroy(rigidBodyInfo); 175 176 this._x = 0; 177 this._y = 0; 178 this._z = 0; 179 this._scaleX = 1; 180 this._scaleY = 1; 181 this._scaleZ = 1; 182 this._mass = mass; 183 this._restitution = 0.3; 184 this._friction = 0.3; 185 }, 186 /** 187 * Expand and contract Rigid. 188 * Expand or contract each axis the designated amount from the current rate of expansion in World. 189 * @param {Number} x Rate of expansion on x axis. 190 * @param {Number} y Rate of expansion on y axis. 191 * @param {Number} z Rate of expansion on z axis. 192 */ 193 scale: function(x, y, z) { 194 this.activate(); 195 this._scaleX *= x; 196 this._scaleY *= y; 197 this._scaleZ *= z; 198 var sv = new Ammo.btVector3(this._scaleX, this._scaleY, this._scaleZ); 199 this.shape.setLocalScaling(sv); 200 Ammo.destroy(sv); 201 }, 202 _scaleAxis: function(axis, scale) { 203 axis.toUpperCase(); 204 this['_scale' + axis] = scale; 205 var sv = new Ammo.btVector3(this._scaleX, this._scaleY, this._scaleZ); 206 this.shape.setLocalScaling(sv); 207 Ammo.destroy(sv); 208 }, 209 /** 210 * Move Rigid in a parallel direciton. 211 * Move the designated amount in a parallel direction along each axis from the current World position. 212 * @param {Number} x Amount of parallel movement along x axis. 213 * @param {Number} y Amount of parallel movement along y axis. 214 * @param {Number} z Amount of parallel movement along z axis. 215 */ 216 translate: function(x, y, z) { 217 this.activate(); 218 var vec = new Ammo.btVector3(x, y, z); 219 this.rigidBody.translate(vec); 220 Ammo.destroy(vec); 221 this._x += x; 222 this._y += y; 223 this._z += z; 224 }, 225 _translateAxis: function(axis, n) { 226 this.activate(); 227 var x = 0; 228 var y = 0; 229 var z = 0; 230 if (axis === 'x') { 231 x = n - this._x; 232 this._x = n; 233 } else if (axis === 'y') { 234 y = n - this._y; 235 this._y = n; 236 } else if (axis === 'z') { 237 z = n - this._z; 238 this._z = n; 239 } 240 var vec = new Ammo.btVector3(x, y, z); 241 this.rigidBody.translate(vec); 242 Ammo.destroy(vec); 243 }, 244 /** 245 * Set posture expressed in quaternion in Rigid. 246 * @param {enchant.gl.Quat} quat 247 */ 248 rotationSet: function(quat) { 249 var qq = quat._quat; 250 var q = new Ammo.btQuaternion(qq[0], qq[1], qq[2], qq[3]); 251 var t = this._getTransform(); 252 t.setRotation(q); 253 this.rigidBody.setWorldTransform(t); 254 Ammo.destroy(q); 255 Ammo.destroy(t); 256 }, 257 /** 258 * Applies rotation expressed in quaternion to Rigid. 259 * @param {enchant.gl.Quat} quat 260 */ 261 rotationApply: function(quat) { 262 var quat1 = quat._quat; 263 var t = this._getTransform(); 264 var qq = t.getRotation(); 265 var quat2 = quat4.create([qq.x(), qq.y(), qq.z(), qq.w()]); 266 quat4.multiply(quat2, quat1, quat2); 267 var q = new Ammo.btQuaternion(quat2[0], quat2[1], quat2[2], quat2[3]); 268 t.setRotation(q); 269 this.rigidBody.setWorldTransform(t); 270 Ammo.destroy(q); 271 Ammo.destroy(t); 272 }, 273 /** 274 * Stops Rigid object. 275 */ 276 clearForces: function() { 277 var vec0 = new Ammo.btVector3(0, 0, 0); 278 this.rigidBody.setLinearVelocity(vec0); 279 this.rigidBody.setAngularVelocity(vec0); 280 this.rigidBody.clearForces(); 281 Ammo.destroy(vec0); 282 }, 283 /** 284 * Collision detection with another Rigid object. 285 * @param {enchant.gl.physics.Rigid} rigid Rigid to be judged. 286 * @return {Boolean} bool Presence or absence of rigid. 287 */ 288 contactTest: function(rigid) { 289 if (this.world && rigid.world && 290 this.world === rigid.world) { 291 return this.world.contactPairTest(this, rigid); 292 } else { 293 return false; 294 } 295 }, 296 /** 297 * Make Rigid valid. 298 * @param {Boolean} force Forcibly make valid. 299 */ 300 activate: function(force) { 301 this.rigidBody.activate(force); 302 }, 303 /** 304 * Add power to Rigid. 305 * Power is added to the center of Rigid. 306 * @param {Number} powerX Power in x axis. 307 * @param {Number} powerY Power in y axis. 308 * @param {Number} powerZ Power in z axis. 309 */ 310 applyCentralImpulse: function(powx, powy, powz) { 311 var powv = new Ammo.btVector3(powx, powy, powz); 312 this.activate(); 313 this.rigidBody.applyCentralImpulse(powv); 314 Ammo.destroy(powv); 315 }, 316 /** 317 * Add power to Rigid. 318 * Power is added to the specified position. 319 * @param {Number} powerX x axis power. 320 * @param {Number} powerY y axis power. 321 * @param {Number} powerZ z axis power. 322 * @param {Number} positonX Coordinate on x axis to add power to. 323 * @param {Number} positonY Coordinate on y axis to add power to. 324 * @param {Number} positonZ Coordinate on z axis to add power to. 325 */ 326 applyImpulse: function(powx, powy, powz, posx, posy, posz) { 327 var powv = new Ammo.btVector3(powx, powy, powz); 328 var posv = new Ammo.btVector3(posx, posy, posz); 329 this.activate(); 330 this.rigidBody.applyImpulse(powv, posv); 331 Ammo.destroy(powv); 332 Ammo.destroy(posv); 333 }, 334 _getTransform: function() { 335 return this.rigidBody.getWorldTransform(); 336 }, 337 /** 338 * Kinematize Rigid. 339 */ 340 kinematize: function() { 341 var flag = this.rigidBody.getCollisionFlags(); 342 this.rigidBody.setCollisionFlags(flag | 2); 343 this.rigidBody.setActivationState(4); 344 }, 345 /** 346 * Rigid restitutions. 347 * @type Number 348 */ 349 restitution: { 350 get: function() { 351 return this._restitution; 352 }, 353 set: function(n) { 354 this._restitution = n; 355 this.rigidBody.setRestitution(n); 356 } 357 }, 358 /** 359 * Rigid frictions. 360 * @type Number 361 */ 362 friction: { 363 get: function() { 364 return this._friction; 365 }, 366 set: function(n) { 367 this._friction = n; 368 this.rigidBody.setFriction(n); 369 } 370 } 371 }); 372 enchant.gl.physics.Rigid._refs = {}; 373 374 /** 375 * @scope enchant.gl.physics.RigidBox.prototype 376 */ 377 enchant.gl.physics.RigidBox = enchant.Class.create(enchant.gl.physics.Rigid, { 378 /** 379 * Rectangular solid rigid body object. 380 * @param {Number} scaleX Vertical distance along the x axis from rectangular body's center. 381 * @param {Number} scaleY Vertical distance along the y axis from rectangular body's center. 382 * @param {Number} scaleZ Vertical distance along the z axis from rectangular body's center. 383 * @param {Number} mass Rigid body's mass. 384 * @see enchant.gl.physics.Rigid 385 * @see enchant.gl.physics.PhyBox 386 * @constructs 387 * @extends enchant.gl.physics.Rigid 388 */ 389 initialize: function(sx, sy, sz, mass) { 390 var scale = new Ammo.btVector3(sx, sy, sz); 391 var shape = new Ammo.btBoxShape(scale); 392 enchant.gl.physics.Rigid.call(this, shape, mass); 393 Ammo.destroy(scale); 394 } 395 }); 396 /** 397 * @scope enchant.gl.physics.RigidCube.prototype 398 */ 399 enchant.gl.physics.RigidCube = enchant.Class.create(enchant.gl.physics.RigidBox, { 400 /** 401 * Rectangular solid rigid object. 402 * @param {Number} scale Distance between center of box and surface. 403 * @param {Number} mass Rigid body mass. 404 * @see enchant.gl.physics.PhyCube 405 * @constructs 406 * @see enchant.gl.physics.Rigid 407 * @extends enchant.gl.physics.PhyCube 408 */ 409 initialize: function(scale, mass) { 410 enchant.gl.physics.RigidBox.call(this, scale, scale, scale, mass); 411 } 412 }); 413 414 /** 415 * @scope enchant.gl.physics.RigidSphere.prototype 416 */ 417 enchant.gl.physics.RigidSphere = enchant.Class.create(enchant.gl.physics.Rigid, { 418 /** 419 * Spherical rigid object. 420 * @param {Number} radius Sphere radius. 421 * @param {Number} mass Rigid body mass. 422 * @see enchant.gl.physics.Rigid 423 * @see enchant.gl.physics.PhySphere 424 * @constructs 425 * @extends enchant.gl.physics.Rigid 426 */ 427 initialize: function(s, mass, lDamp, aDamp) { 428 var shape = new Ammo.btSphereShape(s); 429 enchant.gl.physics.Rigid.call(this, shape, mass, lDamp, aDamp); 430 } 431 }); 432 433 /** 434 * @scope enchant.gl.physics.RigidCylinder.prototype 435 */ 436 enchant.gl.physics.RigidCylinder = enchant.Class.create(enchant.gl.physics.Rigid, { 437 /** 438 * Cylindrical rigid object. 439 * @param {Number} radius Cylinder radius. 440 * @param {Number} height Cylinder height. 441 * @param {Number} mass Rigid object mass. 442 * @see enchant.gl.physics.Rigid 443 * @see enchant.gl.physics.PhyCylinder 444 * @constructs 445 * @extends enchant.gl.physics.Rigid 446 */ 447 initialize: function(r, h, mass) { 448 var scale = new Ammo.btVector3(r, h, r); 449 var shape = new Ammo.btCylinderShape(scale); 450 enchant.gl.physics.Rigid.call(this, shape, mass); 451 Ammo.destroy(scale); 452 } 453 }); 454 455 /** 456 * @scope enchant.gl.physics.RigidCapsule.prototype 457 */ 458 enchant.gl.physics.RigidCapsule = enchant.Class.create(enchant.gl.physics.Rigid, { 459 /** 460 * Capsule-shaped rigid object. 461 * A shape with a cylinder running along the y axis and hemispheres at both ends. 462 * @param {Number} radius Hemisphere radius. 463 * @param {Number} height Half the height of the cylinder. 464 * @param {Number} mass Mass of the rigid object. 465 * @see enchant.gl.physics.Rigid 466 * @see enchant.gl.physics.PhyCapsule 467 * @constructs 468 * @extends enchant.gl.physics.Rigid 469 */ 470 initialize: function(r, h, mass) { 471 var shape = new Ammo.btCapsuleShape(r, h); 472 enchant.gl.physics.Rigid.call(this, shape, mass); 473 } 474 }); 475 476 /** 477 * @scope enchant.gl.physics.RigidPlane.prototype 478 */ 479 enchant.gl.physics.RigidPlane = enchant.Class.create(enchant.gl.physics.Rigid, { 480 /** 481 * Infinite level surface rigid body object. 482 * @param {Number} NormalX Level surface normal vector x component. 483 * @param {Number} NormalY Level surface normal vector y component. 484 * @param {Number} NormalZ Level surface normal vector z component. 485 * @see enchant.gl.physics.Rigid 486 * @see enchant.gl.physics.PhyPlane 487 * @constructs 488 * @extends enchant.gl.physics.Rigid 489 */ 490 initialize: function(nx, ny, nz, distance) { 491 var normal = new Ammo.btVector3(nx, ny, nz); 492 var shape = new Ammo.btStaticPlaneShape(normal, distance); 493 enchant.gl.physics.Rigid.call(this, shape, 0); 494 Ammo.destroy(normal); 495 } 496 }); 497 498 /** 499 * @scope enchant.gl.physics.RigidContainer.prototype 500 */ 501 enchant.gl.physics.RigidContainer = enchant.Class.create(enchant.gl.physics.Rigid, { 502 /** 503 * Box shape solid object. 504 * @param {Number} scale Distance between center of box to border. 505 * @param {Number} mass Mass of rigid object. 506 * @see enchant.gl.physics.Rigid 507 * @see enchant.gl.physics.PhyContainer 508 * @constructs 509 * @extends enchant.gl.physics.Rigid 510 */ 511 initialize: function(s, mass) { 512 var shape = new Ammo.btCompoundShape(s); 513 var addWall = function(sx, sy, sz, px, py, pz) { 514 var sc = new Ammo.btVector3(sx, sy, sz); 515 var tr = new Ammo.btTransform(); 516 tr.setIdentity(); 517 var or = new Ammo.btVector3(px, py, pz); 518 tr.setOrigin(or); 519 var shp = new Ammo.btBoxShape(sc); 520 shape.addChildShape(tr, shp); 521 Ammo.destroy(sc); 522 Ammo.destroy(or); 523 Ammo.destroy(tr); 524 }; 525 addWall(s, s / 8, s, 0, s / 8 - s, 0); 526 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, s / 8, 0, s / 8 - s); 527 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, -s / 8, 0, s - s / 8); 528 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s / 8 - s, 0, -s / 8); 529 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s - s / 8, 0, s / 8); 530 enchant.gl.physics.Rigid.call(this, shape, mass); 531 } 532 }); 533 534 /** 535 * @scope enchant.gl.physics.PhyScene3D.prototype 536 */ 537 enchant.gl.physics.PhyScene3D = enchant.Class.create(enchant.gl.Scene3D, { 538 /** 539 * Scene3D containing World. 540 * As time passes, physical calculation will be applied to the Sprite3D effected by addChild. 541 * @see enchant.gl.physics.World 542 * @constructs 543 * @extends enchant.gl.Scene3D 544 */ 545 initialize: function() { 546 enchant.gl.Scene3D.call(this); 547 var core = enchant.Core.instance; 548 this.world = new enchant.gl.physics.World(); 549 this.isPlaying = false; 550 this.timeStep = 1 / core.fps; 551 this.maxSubSteps = 1; 552 this.fixedTimeStep = 1 / 60; 553 var that = this; 554 this._stepping = function() { 555 that.stepSimulation(that.timeStep, that.maxSubSteps, that.fixedTimeStep); 556 }; 557 }, 558 /** 559 * Add child Sprite3D. 560 * When adding PhySprite3D, the rigid body object containing PhySprite3D will be added to the World containing PhyScene3D. 561 * @param {enchant.gl.Sprite3D|enchant.gl.physics.PhySprite3D} Sprite3D Child Sprite3D to be added. 562 */ 563 addChild: function(sprite) { 564 enchant.gl.Scene3D.prototype.addChild.call(this, sprite); 565 if (sprite instanceof enchant.gl.physics.PhySprite3D) { 566 this.world.addRigid(sprite.rigid); 567 } 568 }, 569 /** 570 * Delete designated child Sprite3D. 571 * When PhySprite3D is set, the rigid body object containing PhySprite3D will be deleted from the World containing PhyScene3D. 572 * @param {enchant.gl.Sprite3D|enchant.gl.physics.PhySprite3D} Sprite3D 追加する子Sprite3D. 573 */ 574 removeChild: function(sprite) { 575 enchant.gl.Scene3D.prototype.removeChild.call(this, sprite); 576 if (sprite instanceof enchant.gl.physics.PhySprite3D) { 577 this.world.removeRigid(sprite.rigid); 578 } 579 }, 580 /** 581 * Set the gravity of World containing PhyScene3D. 582 * @param {Number} gx x axis gravity 583 * @param {Number} gy y axis gravity 584 * @param {Number} gz z axis gravity 585 */ 586 setGravity: function(x, y, z) { 587 this.world.setGravity(x, y, z); 588 }, 589 /** 590 * Proceed forward in time for World containing PhySprite3D. 591 * @param {Number} timeStep Amount of time you wish to proceed. Units are seconds. 592 * @param {Number} maxSubSteps 593 * @param {Number} fixedTimeStep 594 */ 595 stepSimulation: function(timeStep, maxSubSteps, fixedTimeStep) { 596 var subStep = this.world.stepSimulation(timeStep, maxSubSteps, fixedTimeStep); 597 var e = new enchant.Event('timestep'); 598 e.timeStep = timeStep; 599 e.subStep = subStep; 600 this.dispatchEvent(e); 601 for (var i = 0, l = this.childNodes.length; i < l; i++) { 602 if (this.childNodes[i] instanceof enchant.gl.physics.PhySprite3D) { 603 this.childNodes[i].dispatchEvent(e); 604 } 605 } 606 }, 607 /** 608 * Begin World time progress. 609 * Ever other enterframe, stepSimulation will be automaticall called up. 610 */ 611 play: function() { 612 var core = enchant.Core.instance; 613 if (!this.isPlaying) { 614 this.isPlaying = true; 615 core.addEventListener('enterframe', this._stepping); 616 } 617 }, 618 /** 619 * Stop World time progress. 620 */ 621 stop: function() { 622 var core = enchant.Core.instance; 623 this.isPlaying = false; 624 core.removeEventListener('enterframe', this._stepping); 625 } 626 }); 627 628 /** 629 * @scope enchant.gl.physics.PhySprite3D.prototype 630 */ 631 enchant.gl.physics.PhySprite3D = enchant.Class.create(enchant.gl.Sprite3D, { 632 /** 633 * Physical Sprite. 634 * If you add to PhySprite3D, physical calculation will be applied when stepSimulation is called up. 635 * @param {enchant.gl.physics.Rigid} rigid 636 * @see enchant.gl.physics.PhyBox 637 * @see enchant.gl.physics.PhyCube 638 * @see enchant.gl.physics.PhySphere 639 * @see enchant.gl.physics.PhyCylinder 640 * @see enchant.gl.physics.PhyCapsule 641 * @see enchant.gl.physics.PhyPlane 642 * @see enchant.gl.physics.PhyContainer 643 * @constructs 644 */ 645 initialize: function(rigid) { 646 enchant.gl.Sprite3D.call(this); 647 this.rigid = rigid; 648 649 this.addEventListener('timestep', function() { 650 var t = this.rigid._getTransform(); 651 var o = t.getOrigin(); 652 var q = t.getRotation(); 653 this._x = this.rigid._x = o.x(); 654 this._y = this.rigid._y = o.y(); 655 this._z = this.rigid._z = o.z(); 656 this._changedTranslation = true; 657 var a = [ q.x(), q.y(), q.z(), q.w() ]; 658 var quat = quat4.create(a); 659 quat4.toMat4(quat, this.rotation); 660 Ammo.destroy(t); 661 }); 662 }, 663 /** 664 * Expand and contract PhySprite3D. 665 * The expansion rate displayed on the expansion rate in World will be changed at the same time. 666 * @param {Number} x x axis expansion rate. 667 * @param {Number} y y axis expansion rate. 668 * @param {Number} z z axis expansion rate. 669 */ 670 scale: function(x, y, z) { 671 enchant.gl.Sprite3D.prototype.scale.call(this, x, y, z); 672 this.rigid.scale(x, y, z); 673 }, 674 /** 675 * Move PhySprite3D horizontally. 676 * Displayed position and World position will be changed. 677 * @param {Number} x Amount of parallel movement on x axis. 678 * @param {Number} y Amount of parallel movement on y axis. 679 * @param {Number} z Amount of parallel movement on z axis. 680 */ 681 translate: function(x, y, z) { 682 enchant.gl.Sprite3D.prototype.translate.call(this, x, y, z); 683 this.rigid.translate(x, y, z); 684 }, 685 /** 686 * Set rotation line acquired from quaternion in rotation line. 687 * Posture in World will also be changed. 688 * @param {enchant.gl.Quat} quat 689 */ 690 rotationSet: function(quat) { 691 enchant.gl.Sprite3D.prototype.rotationSet.call(this, quat); 692 this.rigid.rotationSet(quat); 693 }, 694 /** 695 * Rotation line acquired from quaternion is applied in rotation line. 696 * Posture in World will also be changed. 697 * @param {enchant.gl.Quat} quat 698 */ 699 rotationApply: function(quat) { 700 enchant.gl.Sprite3D.prototype.rotationApply.call(this, quat); 701 this.rigid.rotationApply(quat); 702 }, 703 /** 704 */ 705 clearForces: function() { 706 this.rigid.clearForces(); 707 }, 708 /** 709 * Collision detection with another PhySprite3D. 710 * @param {enchant.gl.physics.PhySprite3D} sprite PhySprite3D to be detected. 711 * @return {Boolean} bool Presence or absence of collision. 712 */ 713 contactTest: function(sprite) { 714 return this.rigid.contactTest(sprite.rigid); 715 }, 716 /** 717 * Add power to rigid body. 718 * Power is added to center of rigid body. 719 * @param {Number} powerX Power on x axis. 720 * @param {Number} powerY Power on y axis. 721 * @param {Number} powerZ Power on z axis. 722 * @see enchant.gl.physics.Rigid#applyCentralImpulse 723 */ 724 applyCentralImpulse: function(powx, powy, powz) { 725 this.rigid.applyCentralImpulse(powx, powy, powz); 726 }, 727 /** 728 * Add power to rigid body. 729 * Power is added to designated position. 730 * @param {Number} powerX x axis power. 731 * @param {Number} powerY y axis power. 732 * @param {Number} powerZ z axis power. 733 * @param {Number} positonX x coordinates to which power is added. 734 * @param {Number} positonY y coordinates to which power is added. 735 * @param {Number} positonZ z coordinates to which power is added. 736 * @see enchant.gl.physics.Rigid#applyImpulse 737 */ 738 applyImpulse: function(powx, powy, powz, posx, posy, posz) { 739 this.rigid.applyImpulse(powx, powy, powz, posx, posy, posz); 740 }, 741 /** 742 * Kinematize Rigid. 743 */ 744 kinematize: function() { 745 this.rigid.kinematize(); 746 }, 747 /** 748 * PhySprite3D restitutions. 749 * @type Number 750 * @see enchant.gl.physics.Rigid#restitution 751 */ 752 restitution: { 753 get: function() { 754 return this.rigid._restitution; 755 }, 756 set: function(n) { 757 this.rigid._restitution = n; 758 this.rigid.rigidBody.setRestitution(n); 759 } 760 }, 761 /** 762 * PhySprite3D frictions. 763 * @type Number 764 * @see enchant.gl.physics.Rigid#friction 765 */ 766 friction: { 767 get: function() { 768 return this.rigid._friction; 769 }, 770 set: function(n) { 771 this.rigid._friction = n; 772 this.rigid.rigidBody.setFriction(n); 773 } 774 } 775 }); 776 'x y z'.split(' ').forEach(function(prop) { 777 Object.defineProperty(enchant.gl.physics.PhySprite3D.prototype, prop, { 778 get: function() { 779 return this['_' + prop]; 780 }, 781 set: function(n) { 782 this['_' + prop] = n; 783 this._changedTranslation = true; 784 this.rigid._translateAxis(prop, n); 785 } 786 }); 787 }); 788 'scaleX scaleY scaleZ'.split(' ').forEach(function(prop) { 789 Object.defineProperty(enchant.gl.physics.PhySprite3D.prototype, prop, { 790 get: function() { 791 return this['_' + prop]; 792 }, 793 set: function(scale) { 794 this['_' + prop] = scale; 795 this._changedScale = true; 796 this.rigid._scaleAxis(prop, scale); 797 } 798 }); 799 }); 800 801 /** 802 * @scope enchant.gl.physics.PhyBox.prototype 803 */ 804 enchant.gl.physics.PhyBox = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 805 /** 806 * Rectangular PhySprite3D. 807 * If PhySprite3D is added, physical calculation will be applied each time stepSimulation is called up. 808 * @param {Number} scaleX Distance between center of rectangular body and perpendicular x-axis surface. 809 * @param {Number} scaleY Distance between center of rectangular body and perpendicular y-axis surface. 810 * @param {Number} scaleZ Distance between center of rectangular body and perpendicular z-axis surface. 811 * @param {Number} mass Mass of rigid body. 812 * @see enchant.gl.physics.PhySprite3D 813 * @see enchant.gl.physics.PhyScene3D 814 * @constructs 815 * @extends enchant.gl.physics.PhySprite3D 816 */ 817 initialize: function(sx, sy, sz, mass) { 818 var rigid = new enchant.gl.physics.RigidBox(sx, sy, sz, mass); 819 enchant.gl.physics.PhySprite3D.call(this, rigid); 820 this.mesh = enchant.gl.Mesh.createBox(sx, sy, sz); 821 } 822 }); 823 824 /** 825 * @scope enchant.gl.physics.PhyCube.prototype 826 */ 827 enchant.gl.physics.PhyCube = enchant.Class.create(enchant.gl.physics.PhyBox, { 828 /** 829 * Cubic type PhySprite3D. 830 * If added to PhySprite3D, physical calculation will be applied each time stepSimulation is called up. 831 * @param {Number} scale Distance between center of box and surface. 832 * @param {Number} mass Mass of rigid body. 833 * @see enchant.gl.physics.PhySprite3D 834 * @see enchant.gl.physics.PhyScene3D 835 * @constructs 836 * @extends enchant.gl.physics.PhyBox 837 */ 838 initialize: function(s, mass) { 839 var rigid = new enchant.gl.physics.RigidBox(s, s, s, mass); 840 enchant.gl.physics.PhySprite3D.call(this, rigid); 841 this.mesh = enchant.gl.Mesh.createBox(s, s, s); 842 } 843 }); 844 845 /** 846 * @scope enchant.gl.physics.PhySphere.prototype 847 */ 848 enchant.gl.physics.PhySphere = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 849 /** 850 * Spherical PhySprite3D. 851 * If added to PhySprite3D, physical calculation will be applied each time stepSimulation is called up. 852 * @param {Number} radius Spherical body radius. 853 * @param {Number} mass Rigid body mass. 854 * @see enchant.gl.physics.PhySprite3D 855 * @see enchant.gl.physics.PhyScene3D 856 * @constructs 857 * @extends enchant.gl.physics.PhySprite3D 858 */ 859 initialize: function(r, mass, lDamp, aDamp) { 860 if (typeof lDamp === 'undefined') { 861 lDamp = 0.05; 862 } 863 if (typeof aDamp === 'undefined') { 864 aDamp = 0.05; 865 } 866 var rigid = new enchant.gl.physics.RigidSphere(r, mass, lDamp, aDamp); 867 enchant.gl.physics.PhySprite3D.call(this, rigid); 868 this.mesh = enchant.gl.Mesh.createSphere(r); 869 this.addEventListener('timestep', function(e) { 870 this.rigid.rigidBody.applyDamping(e.timeStep); 871 }); 872 } 873 }); 874 875 /** 876 * @scope enchant.gl.physics.PhyCylinder.prototype 877 */ 878 enchant.gl.physics.PhyCylinder = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 879 /** 880 * Cylindrical PhySprite3D. 881 * If added to PhySprite3D, physical calculation will be applied each time stepSimulation is called up. 882 * @param {Number} radius Cylinder radius. 883 * @param {Number} height Cylinder height. 884 * @param {Number} mass Rigid body mass. 885 * @see enchant.gl.physics.PhySprite3D 886 * @see enchant.gl.physics.PhyScene3D 887 * @constructs 888 * @extends enchant.gl.physics.PhySprite3D 889 */ 890 initialize: function(r, h, mass) { 891 var rigid = new enchant.gl.physics.RigidCylinder(r, h, mass); 892 enchant.gl.physics.PhySprite3D.call(this, rigid); 893 this.mesh = enchant.gl.Mesh.createCylinder(r, h); 894 } 895 }); 896 897 /** 898 * @scope enchant.gl.physics.PhyCapsule.prototype 899 */ 900 enchant.gl.physics.PhyCapsule = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 901 /** 902 * Capsule type PhySprite3D. 903 * A shape with a cylinder running along the y axis and hemispheres at both ends. 904 * If added to PhySprite3D, physical calculation will be applied each time stepSimulation is called up. 905 * @param {Number} radius Hemispherical radius. 906 * @param {Number} height Half the height of cylinder. 907 * @param {Number} mass Rigid body mass. 908 * @see enchant.gl.physics.PhySprite3D 909 * @see enchant.gl.physics.PhyScene3D 910 * @constructs 911 * @extends enchant.gl.physics.PhySprite3D 912 */ 913 initialize: function(r, h, mass) { 914 var rigid = new enchant.gl.physics.RigidCapsule(r, h, mass); 915 enchant.gl.physics.PhySprite3D.call(this, rigid); 916 this.mesh = enchant.gl.Mesh.createCylinder(r, h); 917 this.mesh._join(enchant.gl.Mesh.createSphere(r), 0, h, 0); 918 this.mesh._join(enchant.gl.Mesh.createSphere(r), 0, -h, 0); 919 } 920 }); 921 922 /** 923 * @scope enchant.gl.physics.PhyPlane.prototype 924 */ 925 enchant.gl.physics.PhyPlane = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 926 /** 927 * Infinite plane type PhySprite3D. 928 * If added to PhySprite3D, physical calculation will be performed each time stepSimulation is called up. 929 * @param {Number} NormalX x component on plane normal vector. 930 * @param {Number} NormalY y component on plane normal vector. 931 * @param {Number} NormalZ z component on plane normal vector. 932 * @see enchant.gl.physics.PhySprite3D 933 * @see enchant.gl.physics.PhyScene3D 934 * @constructs 935 * @extends enchant.gl.physics.PhySprite3D 936 */ 937 initialize: function(nx, ny, nz, dist, scale) { 938 if (!scale) { 939 scale = 50; 940 } 941 942 var rigid = new enchant.gl.physics.RigidPlane(nx, ny, nz, dist); 943 enchant.gl.physics.PhySprite3D.call(this, rigid); 944 this.mesh = enchant.gl.Mesh.createPlaneXZ(scale); 945 var up = vec3.create([0, 1, 0]); 946 var norm = vec3.create([nx, ny, nz]); 947 var axis = vec3.create(); 948 vec3.cross(up, norm, axis); 949 var rad = Math.acos(vec3.dot(up, norm) / (vec3.length(up) * vec3.length(norm))); 950 var q = new enchant.gl.Quat(axis[0], axis[1], axis[2], rad); 951 var vertices = []; 952 for (var i = 0, l = this.mesh.vertices.length; i < l; i += 3) { 953 var x = this.mesh.vertices[i]; 954 var y = this.mesh.vertices[i + 1]; 955 var z = this.mesh.vertices[i + 2]; 956 var arr = q.multiplyVec3([x, y, z]); 957 vertices.push(arr[0] + nx * dist); 958 vertices.push(arr[1] + ny * dist); 959 vertices.push(arr[2] + nz * dist); 960 } 961 this.mesh.vertices = vertices; 962 } 963 }); 964 965 /** 966 * @scope enchant.gl.physics.PhyContainer.prototype 967 */ 968 enchant.gl.physics.PhyContainer = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 969 /** 970 * Square type PhySprite3D. 971 * If added to PhySprite3D, physical calculation will be performed each time stepSimulation is called up. 972 * @param {Number} scale Distance between center and edge of square. 973 * @param {Number} mass Rigid body mass. 974 * @see enchant.gl.physics.PhySprite3D 975 * @see enchant.gl.physics.PhyScene3D 976 * @constructs 977 * @extends enchant.gl.physics.PhySprite3D 978 */ 979 initialize: function(scale, mass) { 980 var s = scale; 981 var rigid = new enchant.gl.physics.RigidContainer(s, mass); 982 enchant.gl.physics.PhySprite3D.call(this, rigid); 983 var that = this; 984 this.mesh = new enchant.gl.Mesh(); 985 var addWall = function(sx, sy, sz, px, py, pz) { 986 that.mesh._join(enchant.gl.Mesh.createBox(sx, sy, sz), px, py, pz); 987 }; 988 addWall(s, s / 8, s, 0, s / 8 - s, 0); 989 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, s / 8, 0, s / 8 - s); 990 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, -s / 8, 0, s - s / 8); 991 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s / 8 - s, 0, -s / 8); 992 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s - s / 8, 0, s / 8); 993 } 994 995 }); 996 }()); 997 } 998