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 * ammo.jsを使用している物理演算ライブラリ. 13 * gl.enchant.jsで物理演算によって動作するオブジェクトを使えるようにする. 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 * 物理演算が適用される世界. 34 * ここに剛体オブジェクトを追加し, 時間を進めることで物理演算が実行される. 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 * Worldの重力を設定する. 54 * @param {Number} gx x軸方向の重力. 55 * @param {Number} gy y軸方向の重力. 56 * @param {Number} gz z軸方向の重力. 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 * Worldの時間を進める. 65 * timeStepがfixedTimeStepより大きい場合, maxSubStepで指定した回数まで続けて時間を進める. 66 * @param {Number} timeStep 進めたい時間.単位は秒. 67 * @param {Number} maxSubSteps シミュレーションの最大追加回数. 68 * @param {Number} fixedTimeStep 基本となる時間. デフォルト値は1/60. 69 * @return {Number} subStepsNum 70 */ 71 stepSimulation: function(timeStep, maxSubSteps, fixedTimeStep) { 72 return this._dynamicsWorld.stepSimulation(timeStep, maxSubSteps, fixedTimeStep); 73 }, 74 /** 75 * Worldに剛体を追加する. 76 * @param {enchant.gl.physics.Rigid} Rigid 追加する剛体オブジェクト. 77 */ 78 addRigid: function(rigid) { 79 this._dynamicsWorld.addRigidBody(rigid.rigidBody); 80 rigid.world = this; 81 }, 82 /** 83 * Worldから剛体を削除する. 84 * @param {enchant.gl.physics.Rigid} Rigid 削除する剛体オブジェクト. 85 */ 86 removeRigid: function(rigid) { 87 this._dynamicsWorld.removeRigidBody(rigid.rigidBody); 88 rigid.world = null; 89 }, 90 /** 91 * Rigid同士が衝突しているかを判定する. 92 * @param {enchant.gl.physics.Rigid} rigid1 判定するRigid1. 93 * @param {enchant.gl.physics.Rigid} rigid2 判定するRigid2. 94 * @return {Boolean} bool 衝突の有無. 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 * 剛体オブジェクト. 119 * Worldに追加して使用する. 120 * @param shape Ammo.btCollisionShapeオブジェクト. 121 * @param {Number} mass 剛体の質量. 122 * @param {Number} linearDamping 剛体の線形速度の減衰率. 123 * @param {Number} angularDamping 剛体の角速度の減衰率. 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 * Rigidが所属するWorld 162 */ 163 this.world = null; 164 165 /** 166 * Ammoの剛体オブジェクト 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 * Rigidを拡大縮小する. 188 * Worldでの現在の拡大率から, 各軸に対して指定された倍率分だけ拡大縮小をする. 189 * @param {Number} x x軸方向の拡大率. 190 * @param {Number} y y軸方向の拡大率. 191 * @param {Number} z z軸方向の拡大率. 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 * Rigidを平行移動する. 211 * Worldでの現在の位置から, 各軸に対して指定された分だけ平行移動をする. 212 * @param {Number} x x軸方向の平行移動量. 213 * @param {Number} y y軸方向の平行移動量. 214 * @param {Number} z z軸方向の平行移動量. 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 * クォータニオンで表した姿勢を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 * クォータニオンで表した回転を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 * Rigidを止める. 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 * 他のRigidとの衝突判定. 285 * @param {enchant.gl.physics.Rigid} rigid 判定するRigid. 286 * @return {Boolean} bool 衝突の有無. 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 * Rigidを有効化する. 298 * @param {Boolean} force 強制的に有効化する. 299 */ 300 activate: function(force) { 301 this.rigidBody.activate(force); 302 }, 303 /** 304 * Rigidに力を加える. 305 * 力はRigidの中心に加えられる. 306 * @param {Number} powerX x軸方向の力. 307 * @param {Number} powerY y軸方向の力. 308 * @param {Number} powerZ z軸方向の力. 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 * Rigidに力を加える. 318 * 力は指定した位置に加えられる. 319 * @param {Number} powerX x軸方向の力. 320 * @param {Number} powerY y軸方向の力. 321 * @param {Number} powerZ z軸方向の力. 322 * @param {Number} positonX 力を加える位置のx座標. 323 * @param {Number} positonY 力を加える位置のy座標. 324 * @param {Number} positonZ 力を加える位置のz座標. 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 * 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の反発係数. 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の摩擦係数. 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 * 直方体型の剛体オブジェクト. 380 * @param {Number} scaleX 直方体の中心からx軸に垂直な面までの距離. 381 * @param {Number} scaleY 直方体の中心からy軸に垂直な面までの距離. 382 * @param {Number} scaleZ 直方体の中心からz軸に垂直な面までの距離. 383 * @param {Number} 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 * 立方体型の剛体オブジェクト. 402 * @param {Number} scale 箱の中心から面までの距離. 403 * @param {Number} 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 * 球体型の剛体オブジェクト. 420 * @param {Number} radius 球体の半径. 421 * @param {Number} 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 * 円柱型の剛体オブジェクト. 439 * @param {Number} radius 円柱の半径. 440 * @param {Number} height 円柱の高さ. 441 * @param {Number} 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 * カプセル型の剛体オブジェクト. 461 * y軸に沿う円柱の両端に半球をつけた形状. 462 * @param {Number} radius 半球体の半径. 463 * @param {Number} height 円柱の高さの半分. 464 * @param {Number} mass 剛体の質量. 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 * 無限平面型の剛体オブジェクト. 482 * @param {Number} NormalX 平面の法線ベクトルのx成分. 483 * @param {Number} NormalY 平面の法線ベクトルのy成分. 484 * @param {Number} NormalZ 平面の法線ベクトルのz成分. 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 * 枡型の剛体オブジェクト. 504 * @param {Number} scale 枡の中心から枠までの距離. 505 * @param {Number} mass 剛体の質量. 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 * Worldを持つScene3D. 540 * 時間を進めることで, addChildされたSprite3Dに物理演算が適用される. 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 * 子Sprite3Dを追加する. 560 * PhySprite3Dを追加した場合, PhySprite3Dが持つ剛体オブジェクトがPhyScene3Dが持つWorldに追加される. 561 * @param {enchant.gl.Sprite3D|enchant.gl.physics.PhySprite3D} Sprite3D 追加する子Sprite3D. 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 * 指定された子Sprite3Dを削除する. 571 * PhySprite3Dを指定した場合, PhySprite3Dが持つ剛体オブジェクトがPhyScene3Dが持つWorldから削除される. 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 * PhyScene3Dが持つWorldの重力を設定する。 582 * @param {Number} gx x軸方向の重力 583 * @param {Number} gy y軸方向の重力 584 * @param {Number} gz z軸方向の重力 585 */ 586 setGravity: function(x, y, z) { 587 this.world.setGravity(x, y, z); 588 }, 589 /** 590 * PhySprite3Dが持つWorldの時間を進める. 591 * @param {Number} timeStep 進めたい時間.単位は秒. 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 * Worldの時間の進行を始める. 609 * enterframeごとにstepSimulationが自動で呼び出される. 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 * Worldの時間の進行を止める. 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 * 物理スプライト. 634 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 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 * PhySprite3Dを拡大縮小する. 665 * 表示上の拡大率とWorldでの拡大率が同時に変更される. 666 * @param {Number} x x軸方向の拡大率. 667 * @param {Number} y y軸方向の拡大率. 668 * @param {Number} z z軸方向の拡大率. 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 * PhySprite3Dを平行移動する. 676 * 表示上の位置とWorldでの位置が変更される. 677 * @param {Number} x x軸方向の平行移動量. 678 * @param {Number} y y軸方向の平行移動量. 679 * @param {Number} z z軸方向の平行移動量. 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 * 回転行列にクォータニオンから得られる回転行列をセットする. 687 * Worldでの姿勢も変更される. 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 * 回転行列にクォータニオンから得られる回転行列を適用する. 696 * Worldでの姿勢も変更される. 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 * Rigidを止める. 705 * Stops Rigid object. 706 */ 707 clearForces: function() { 708 this.rigid.clearForces(); 709 }, 710 /** 711 * 他のPhySprite3Dとの衝突判定. 712 * @param {enchant.gl.physics.PhySprite3D} sprite 判定するPhySprite3D. 713 * @return {Boolean} bool 衝突の有無. 714 */ 715 contactTest: function(sprite) { 716 return this.rigid.contactTest(sprite.rigid); 717 }, 718 /** 719 * 剛体に力を加える. 720 * 力は剛体の中心に加えられる. 721 * @param {Number} powerX x軸方向の力. 722 * @param {Number} powerY y軸方向の力. 723 * @param {Number} powerZ z軸方向の力. 724 * @see enchant.gl.physics.Rigid#applyCentralImpulse 725 */ 726 applyCentralImpulse: function(powx, powy, powz) { 727 this.rigid.applyCentralImpulse(powx, powy, powz); 728 }, 729 /** 730 * 剛体に力を加える. 731 * 力は指定した位置に加えられる. 732 * @param {Number} powerX x軸方向の力. 733 * @param {Number} powerY y軸方向の力. 734 * @param {Number} powerZ z軸方向の力. 735 * @param {Number} positonX 力を加える位置のx座標. 736 * @param {Number} positonY 力を加える位置のy座標. 737 * @param {Number} positonZ 力を加える位置のz座標. 738 * @see enchant.gl.physics.Rigid#applyImpulse 739 */ 740 applyImpulse: function(powx, powy, powz, posx, posy, posz) { 741 this.rigid.applyImpulse(powx, powy, powz, posx, posy, posz); 742 }, 743 /** 744 * PhySprite3Dをユーザが動かすためのオブジェクトとして設定する. 745 */ 746 kinematize: function() { 747 this.rigid.kinematize(); 748 }, 749 /** 750 * PhySprite3Dの反発係数. 751 * @type Number 752 * @see enchant.gl.physics.Rigid#restitution 753 */ 754 restitution: { 755 get: function() { 756 return this.rigid._restitution; 757 }, 758 set: function(n) { 759 this.rigid._restitution = n; 760 this.rigid.rigidBody.setRestitution(n); 761 } 762 }, 763 /** 764 * PhySprite3Dの摩擦係数. 765 * @type Number 766 * @see enchant.gl.physics.Rigid#friction 767 */ 768 friction: { 769 get: function() { 770 return this.rigid._friction; 771 }, 772 set: function(n) { 773 this.rigid._friction = n; 774 this.rigid.rigidBody.setFriction(n); 775 } 776 } 777 }); 778 'x y z'.split(' ').forEach(function(prop) { 779 Object.defineProperty(enchant.gl.physics.PhySprite3D.prototype, prop, { 780 get: function() { 781 return this['_' + prop]; 782 }, 783 set: function(n) { 784 this['_' + prop] = n; 785 this._changedTranslation = true; 786 this.rigid._translateAxis(prop, n); 787 } 788 }); 789 }); 790 'scaleX scaleY scaleZ'.split(' ').forEach(function(prop) { 791 Object.defineProperty(enchant.gl.physics.PhySprite3D.prototype, prop, { 792 get: function() { 793 return this['_' + prop]; 794 }, 795 set: function(scale) { 796 this['_' + prop] = scale; 797 this._changedScale = true; 798 this.rigid._scaleAxis(prop, scale); 799 } 800 }); 801 }); 802 803 /** 804 * @scope enchant.gl.physics.PhyBox.prototype 805 */ 806 enchant.gl.physics.PhyBox = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 807 /** 808 * 直方体型のPhySprite3D. 809 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 810 * @param {Number} scaleX 直方体の中心からx軸に垂直な面までの距離. 811 * @param {Number} scaleY 直方体の中心からy軸に垂直な面までの距離. 812 * @param {Number} scaleZ 直方体の中心からz軸に垂直な面までの距離. 813 * @param {Number} mass 剛体の質量. 814 * @see enchant.gl.physics.PhySprite3D 815 * @see enchant.gl.physics.PhyScene3D 816 * @constructs 817 * @extends enchant.gl.physics.PhySprite3D 818 */ 819 initialize: function(sx, sy, sz, mass) { 820 var rigid = new enchant.gl.physics.RigidBox(sx, sy, sz, mass); 821 enchant.gl.physics.PhySprite3D.call(this, rigid); 822 this.mesh = enchant.gl.Mesh.createBox(sx, sy, sz); 823 } 824 }); 825 826 /** 827 * @scope enchant.gl.physics.PhyCube.prototype 828 */ 829 enchant.gl.physics.PhyCube = enchant.Class.create(enchant.gl.physics.PhyBox, { 830 /** 831 * 立方体型のPhySprite3D. 832 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 833 * @param {Number} scale 箱の中心から面までの距離. 834 * @param {Number} mass 剛体の質量. 835 * @see enchant.gl.physics.PhySprite3D 836 * @see enchant.gl.physics.PhyScene3D 837 * @constructs 838 * @extends enchant.gl.physics.PhyBox 839 */ 840 initialize: function(s, mass) { 841 var rigid = new enchant.gl.physics.RigidBox(s, s, s, mass); 842 enchant.gl.physics.PhySprite3D.call(this, rigid); 843 this.mesh = enchant.gl.Mesh.createBox(s, s, s); 844 } 845 }); 846 847 /** 848 * @scope enchant.gl.physics.PhySphere.prototype 849 */ 850 enchant.gl.physics.PhySphere = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 851 /** 852 * 球体型のPhySprite3D. 853 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 854 * @param {Number} radius 球体の半径. 855 * @param {Number} mass 剛体の質量. 856 * @see enchant.gl.physics.PhySprite3D 857 * @see enchant.gl.physics.PhyScene3D 858 * @constructs 859 * @extends enchant.gl.physics.PhySprite3D 860 */ 861 initialize: function(r, mass, lDamp, aDamp) { 862 if (typeof lDamp === 'undefined') { 863 lDamp = 0.05; 864 } 865 if (typeof aDamp === 'undefined') { 866 aDamp = 0.05; 867 } 868 var rigid = new enchant.gl.physics.RigidSphere(r, mass, lDamp, aDamp); 869 enchant.gl.physics.PhySprite3D.call(this, rigid); 870 this.mesh = enchant.gl.Mesh.createSphere(r); 871 this.addEventListener('timestep', function(e) { 872 this.rigid.rigidBody.applyDamping(e.timeStep); 873 }); 874 } 875 }); 876 877 /** 878 * @scope enchant.gl.physics.PhyCylinder.prototype 879 */ 880 enchant.gl.physics.PhyCylinder = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 881 /** 882 * 円柱型のPhySprite3D. 883 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 884 * @param {Number} radius 円柱の半径. 885 * @param {Number} height 円柱の高さ. 886 * @param {Number} mass 剛体の質量. 887 * @see enchant.gl.physics.PhySprite3D 888 * @see enchant.gl.physics.PhyScene3D 889 * @constructs 890 * @extends enchant.gl.physics.PhySprite3D 891 */ 892 initialize: function(r, h, mass) { 893 var rigid = new enchant.gl.physics.RigidCylinder(r, h, mass); 894 enchant.gl.physics.PhySprite3D.call(this, rigid); 895 this.mesh = enchant.gl.Mesh.createCylinder(r, h); 896 } 897 }); 898 899 /** 900 * @scope enchant.gl.physics.PhyCapsule.prototype 901 */ 902 enchant.gl.physics.PhyCapsule = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 903 /** 904 * カプセル型のPhySprite3D. 905 * y軸に沿う円柱の両端に半球をつけた形状. 906 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 907 * @param {Number} radius 半球体の半径. 908 * @param {Number} height 円柱の高さの半分. 909 * @param {Number} mass 剛体の質量. 910 * @see enchant.gl.physics.PhySprite3D 911 * @see enchant.gl.physics.PhyScene3D 912 * @constructs 913 * @extends enchant.gl.physics.PhySprite3D 914 */ 915 initialize: function(r, h, mass) { 916 var rigid = new enchant.gl.physics.RigidCapsule(r, h, mass); 917 enchant.gl.physics.PhySprite3D.call(this, rigid); 918 this.mesh = enchant.gl.Mesh.createCylinder(r, h); 919 this.mesh._join(enchant.gl.Mesh.createSphere(r), 0, h, 0); 920 this.mesh._join(enchant.gl.Mesh.createSphere(r), 0, -h, 0); 921 } 922 }); 923 924 /** 925 * @scope enchant.gl.physics.PhyPlane.prototype 926 */ 927 enchant.gl.physics.PhyPlane = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 928 /** 929 * 無限平面型のPhySprite3D. 930 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 931 * @param {Number} NormalX 平面の法線ベクトルのx成分. 932 * @param {Number} NormalY 平面の法線ベクトルのy成分. 933 * @param {Number} NormalZ 平面の法線ベクトルのz成分. 934 * @see enchant.gl.physics.PhySprite3D 935 * @see enchant.gl.physics.PhyScene3D 936 * @constructs 937 * @extends enchant.gl.physics.PhySprite3D 938 */ 939 initialize: function(nx, ny, nz, dist, scale) { 940 if (!scale) { 941 scale = 50; 942 } 943 944 var rigid = new enchant.gl.physics.RigidPlane(nx, ny, nz, dist); 945 enchant.gl.physics.PhySprite3D.call(this, rigid); 946 this.mesh = enchant.gl.Mesh.createPlaneXZ(scale); 947 var up = vec3.create([0, 1, 0]); 948 var norm = vec3.create([nx, ny, nz]); 949 var axis = vec3.create(); 950 vec3.cross(up, norm, axis); 951 var rad = Math.acos(vec3.dot(up, norm) / (vec3.length(up) * vec3.length(norm))); 952 var q = new enchant.gl.Quat(axis[0], axis[1], axis[2], rad); 953 var vertices = []; 954 for (var i = 0, l = this.mesh.vertices.length; i < l; i += 3) { 955 var x = this.mesh.vertices[i]; 956 var y = this.mesh.vertices[i + 1]; 957 var z = this.mesh.vertices[i + 2]; 958 var arr = q.multiplyVec3([x, y, z]); 959 vertices.push(arr[0] + nx * dist); 960 vertices.push(arr[1] + ny * dist); 961 vertices.push(arr[2] + nz * dist); 962 } 963 this.mesh.vertices = vertices; 964 } 965 }); 966 967 /** 968 * @scope enchant.gl.physics.PhyContainer.prototype 969 */ 970 enchant.gl.physics.PhyContainer = enchant.Class.create(enchant.gl.physics.PhySprite3D, { 971 /** 972 * 枡型のPhySprite3D. 973 * PhySprite3Dに追加すると, stepSimulationを呼び出した際に物理演算が適用される. 974 * @param {Number} scale 枡の中心から枠までの距離. 975 * @param {Number} mass 剛体の質量. 976 * @see enchant.gl.physics.PhySprite3D 977 * @see enchant.gl.physics.PhyScene3D 978 * @constructs 979 * @extends enchant.gl.physics.PhySprite3D 980 */ 981 initialize: function(scale, mass) { 982 var s = scale; 983 var rigid = new enchant.gl.physics.RigidContainer(s, mass); 984 enchant.gl.physics.PhySprite3D.call(this, rigid); 985 var that = this; 986 this.mesh = new enchant.gl.Mesh(); 987 var addWall = function(sx, sy, sz, px, py, pz) { 988 that.mesh._join(enchant.gl.Mesh.createBox(sx, sy, sz), px, py, pz); 989 }; 990 addWall(s, s / 8, s, 0, s / 8 - s, 0); 991 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, s / 8, 0, s / 8 - s); 992 addWall(s - s / 8, s - s / 8 - s / 8, s / 8, -s / 8, 0, s - s / 8); 993 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s / 8 - s, 0, -s / 8); 994 addWall(s / 8, s - s / 8 - s / 8, s - s / 8, s - s / 8, 0, s / 8); 995 } 996 997 }); 998 }()); 999 } 1000