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