1 /**
  2 * PhySprite.enchant.js
  3 * @version 1.52
  4 * @require enchant.js v0.4.3 or later
  5 * @require Box2dWeb.js
  6 * @author kassy708 http://twitter.com/kassy708
  7 *
  8 * @description
  9 * 物理演算用のSprite
 10 * このプラグインではBox2dWeb.jsを用いています。
 11 * 最新のBox2dWeb.jsは下記アドレスからダウンロードしてください。
 12 * http://www.gphysics.com/
 13 *
 14 * @license
 15 * The MIT License
 16 * Copyright (c) 2012/01/26 kassy708
 17 *
 18 * Permission is hereby granted, free of charge, to any person obtaining a copy
 19 * of this software and associated documentation files (the "Software"), to deal
 20 * in the Software without restriction, including without limitation the rights
 21 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 22 * copies of the Software, and to permit persons to whom the Software is
 23 * furnished to do so, subject to the following conditions:
 24 *
 25 * The above copyright notice and this permission notice shall be included in
 26 * all copies or substantial portions of the Software.
 27 *
 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 30 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
 31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 33 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 34 * THE SOFTWARE.
 35 */
 36 
 37 /**
 38 * 長さの単位,pxとmの大きさの比率
 39 */
 40 var WORLD_SCALE = 32;
 41 /**
 42 * 物理ワールド
 43 */
 44 var world = null;
 45 
 46 /**
 47 * スプライトの輪郭の色
 48 */
 49 var DebugDrawStrokeColor = 'black';
 50 /**
 51 * スプライトの塗りつぶしの色
 52 */
 53 var DebugDrawFillColor = 'white';
 54 /**
 55 * ジョイントの色
 56 */
 57 var DrawJointColor = '#00eeee';
 58 
 59 
 60 
 61 var b2Vec2 = Box2D.Common.Math.b2Vec2
 62 , b2AABB = Box2D.Collision.b2AABB
 63 , b2BodyDef = Box2D.Dynamics.b2BodyDef
 64 , b2Body = Box2D.Dynamics.b2Body
 65 , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
 66 , b2Fixture = Box2D.Dynamics.b2Fixture
 67 , b2World = Box2D.Dynamics.b2World
 68 , b2MassData = Box2D.Collision.Shapes.b2MassData
 69 , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
 70 , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
 71 , b2Shape = Box2D.Collision.Shapes.b2Shape
 72 , b2DebugDraw = Box2D.Dynamics.b2DebugDraw
 73 , b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef
 74 , b2Math = Box2D.Common.Math.b2Math
 75 , b2Joint = Box2D.Dynamics.Joints.b2Joint
 76 , b2DistanceJointDef = Box2D.Dynamics.Joints.b2DistanceJointDef
 77 , b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef
 78 , b2PulleyJointDef = Box2D.Dynamics.Joints.b2PulleyJointDef
 79 , b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef
 80 , b2GearJointDef = Box2D.Dynamics.Joints.b2GearJointDef
 81 ;
 82 
 83 
 84 /**
 85 * Spriteの種類(スタティック)
 86 * @type {Number}
 87 */
 88 var STATIC_SPRITE = b2Body.b2_staticBody;
 89 /**
 90 * Spriteの種類(ダイナミック)
 91 * @type {Number}
 92 */
 93 var DYNAMIC_SPRITE = b2Body.b2_dynamicBody;
 94 /**
 95 * Spriteの種類(キネマティック)
 96 * @type {Number}
 97 */
 98 var KINEMATIC_SPRITE = b2Body.b2_kinematicBody;
 99 
100 /**
101 * @scope enchant.PhysicsWorld.prototype
102 */
103 enchant.PhysicsWorld = enchant.Class.create({
104     /**
105     * 物理シミュレーションを行う世界のクラス
106     * @example
107     *   //y軸方向へ重力加速度9.8m/s^2
108     *   var physicsWorld = new PhysicsWorld(0, 9.8);
109     *   //無重力
110     *   var physicsWorld = new PhysicsWorld(0, 0);
111     * 
112     * @param {Number} [gravityX] x軸方向への引力.
113     * @param {Number} [gravityY] y軸方向への引力.
114     * @constructs
115     */
116     initialize: function (gravityX, gravityY) {
117         var game = enchant.Game.instance;
118         this.jointShowSurface = new Surface(game.width, game.height);
119         /**
120         * 物理シミュレーションの精度
121         * @type {Nunber}
122         */
123         this.iterations = 10;
124         world = new b2World(
125             new b2Vec2(gravityX, gravityY)  //gravity
126             , true                          //allow sleep
127         );
128     },
129     /**
130     * 物理シミュレーション内の時間を進める
131     * @param {b2Vec2} [pos] Spriteの座標.
132     */
133     step: function (fps) {
134         world.Step(1 / fps, this.iterations, this.iterations);
135     },
136     /**
137     * 物体の当たり判定
138     * @example
139     *   //ぶつかった2つのSpriteを消す
140     *   physicsWorld.contact(function (sprite1, sprite2) {
141     *       sprite1.destroy();
142     *       sprite2.destroy(); 
143     *   });
144     *
145     * @param {function(sprite1:enchant.PhySprite,sprite2:enchant.PhySprite)} [func] 当たり判定時の処理
146     */
147     contact: function (func) {
148         var c = world.m_contactList;
149         if (c) {
150             for (var contact = c; contact; contact = contact.m_next) {
151                 var pos1 = contact.m_fixtureA.m_body.GetPosition().Copy();
152                 pos1.Subtract(contact.m_fixtureB.m_body.GetPosition());
153                 pos1.Multiply(WORLD_SCALE);
154                 var r1 = (contact.m_fixtureA.m_body.m_userData.width + contact.m_fixtureB.m_body.m_userData.width) / 2;
155                 var r2 = (contact.m_fixtureA.m_body.m_userData.height + contact.m_fixtureB.m_body.m_userData.height) / 2;
156                 if (Math.abs(pos1.x) <= r1 && Math.abs(pos1.y) <= r2) {
157                     func(contact.m_fixtureA.m_body.m_userData, contact.m_fixtureB.m_body.m_userData);
158                 }
159             }
160         }
161     },
162     getJointImage: function () {
163         var surface = this.jointShowSurface;
164         surface.context.clearRect(0, 0, surface.width, surface.height);
165         var drawJoint = function (joint) {
166             var b1 = joint.m_bodyA;
167             var b2 = joint.m_bodyB;
168             var x1 = b1.GetPosition().Copy();
169             var x2 = b2.GetPosition().Copy();
170             var p1 = joint.GetAnchorA().Copy();
171             var p2 = joint.GetAnchorB().Copy();
172             x1.Multiply(WORLD_SCALE);
173             x2.Multiply(WORLD_SCALE);
174             p1.Multiply(WORLD_SCALE);
175             p2.Multiply(WORLD_SCALE);
176             surface.context.strokeStyle = DrawJointColor;
177             surface.context.beginPath();
178             switch (joint.m_type) {
179                 case b2Joint.e_distanceJoint:
180                     surface.context.moveTo(p1.x, p1.y);
181                     surface.context.lineTo(p2.x, p2.y);
182                     break;
183 
184                 case b2Joint.e_pulleyJoint:
185                     var gu1 = joint.GetGroundAnchorA().Copy();
186                     var gu2 = joint.GetGroundAnchorB().Copy();
187                     gu1.Multiply(WORLD_SCALE);
188                     gu2.Multiply(WORLD_SCALE);
189                     surface.context.moveTo(x1.x, x1.y);
190                     surface.context.lineTo(p1.x, p1.y);
191                     surface.context.lineTo(gu1.x, gu1.y);
192                     surface.context.lineTo(gu2.x, gu2.y);
193                     surface.context.lineTo(x2.x, x2.y);
194                     surface.context.lineTo(p2.x, p2.y);
195                     break;
196 
197                 default:
198                     if (b1 == world.m_groundBody) {
199                         surface.context.moveTo(p1.x, p1.y);
200                         surface.context.lineTo(x2.x, x2.y);
201                     }
202                     else if (b2 == world.m_groundBody) {
203                         surface.context.moveTo(p1.x, p1.y);
204                         surface.context.lineTo(x1.x, x1.y);
205                     }
206                     else {
207                         surface.context.moveTo(x1.x, x1.y);
208                         surface.context.lineTo(p1.x, p1.y);
209                         surface.context.lineTo(x2.x, x2.y);
210                         surface.context.lineTo(p2.x, p2.y);
211                     }
212                     break;
213             }
214             surface.context.stroke();
215         };
216         for (var j = world.m_jointList; j; j = j.m_next) {
217             drawJoint(j);
218         }
219         return surface;
220     },
221     /**
222     * ワールドにあるすべてのオブジェクトを削除
223     * シーンの切り替わり時に呼んでおかないと、次のシーンでも衝突判定がおこってしまう。
224     */
225     cleanAllSprite: function () {
226         var body = world.m_bodyList;
227         var nextBody;
228         while (body) {
229             nextBody = body.m_next;
230             if (body.m_userData) {
231                 body.m_userData.destroy();
232             }
233             else {
234                 world.DestroyBody(body);
235             }
236             body = nextBody;
237         }
238     },
239     /**
240     * ワールドにあるすべてのジョイントを削除
241     */
242     cleanAllJoint: function () {
243         var joint = world.m_jointList;
244         var nextJoint;
245         while (joint) {
246             nextJoint = joint.m_next;
247             if (joint.m_userData) {
248                 joint.m_userData.destroy();
249             }
250             else {
251                 world.DestroyJoint(joint);
252             }
253             joint = nextJoint;
254         }
255     },
256     /**
257     * ワールドのすべてを削除
258     */
259     cleanUp: function () {
260         this.cleanAllJoint();
261         this.cleanAllSprite();
262     }
263 });
264 
265 
266 /**
267 * @scope enchant.PhySprite.prototype
268 */
269 enchant.PhySprite = enchant.Class.create(enchant.Sprite, {
270     /**
271     * 画像表示機能を持った物理シミュレーションクラス.
272     * @param {Number} [width] Spriteの横幅.
273     * @param {Number} [height] Spriteの高さ.
274     * @constructs
275     * @extends enchant.Sprite
276     */
277     initialize: function (width, height) {
278         this.body;
279         enchant.Sprite.call(this, width, height);
280 
281         var time = 0;
282         this.addEventListener(enchant.Event.ENTER_FRAME, function (e) {
283             this.x = this.x;
284             this.y = this.y;
285             if (time % 2) {   //なぜか移動と回転を一緒にできない。謎。
286                 this.rotation = this.angle;
287             }
288             time = (time + 1) % 2;
289         });
290     },
291     /**
292     * 四角形の物理シミュレーション用Sprite生成.
293     * @param {Boolean} type 静的,動的,キネマティック
294     * @param {Number} density Spriteの密度.
295     * @param {Number} friction Spriteの摩擦.
296     * @param {Number} restitution Spriteの反発.
297     * @param {Boolean} awake Spriteが初めから物理演算を行うか.
298     */
299     createPhyBox: function (type, density, friction, restitution, awake) {
300         var fixDef = new b2FixtureDef;
301         fixDef.density = (density !== undefined ? density : 1.0);             // 密度
302         fixDef.friction = (friction !== undefined ? friction : 0.5);          // 摩擦
303         fixDef.restitution = (restitution !== undefined ? restitution : 0.3); // 反発
304         fixDef.shape = new b2PolygonShape;
305         fixDef.shape.SetAsBox(this.width / 2 / WORLD_SCALE, this.height / 2 / WORLD_SCALE);
306         var bodyDef = new b2BodyDef;
307         bodyDef.type = type;
308         bodyDef.position.x = 0;
309         bodyDef.position.y = 0;
310         bodyDef.awake = (awake !== undefined ? awake : true);
311         bodyDef.userData = this;
312         this.body = world.CreateBody(bodyDef).CreateFixture(fixDef);
313         this.setDegugImage();
314         return this.body;
315     },
316     /**
317     * 多角形の物理シミュレーション用Sprite生成.
318     * @param {b2Vec2[]} vertexs 多角形の頂点配列
319     * @param {Boolean} type 静的,動的,キネマティック
320     * @param {Number} density Spriteの密度.
321     * @param {Number} friction Spriteの摩擦.
322     * @param {Number} restitution Spriteの反発.
323     * @param {Boolean} awake Spriteが初めから物理演算を行うか.
324     */
325     createPhyPolygon: function (vertexs, type, density, friction, restitution, awake) {
326         for (var i = 0; i < vertexs.length; i++) {
327             vertexs[i].Multiply(1 / WORLD_SCALE);
328         }
329         var fixDef = new b2FixtureDef;
330         fixDef.density = (density !== undefined ? density : 1.0);             // 密度
331         fixDef.friction = (friction !== undefined ? friction : 0.5);          // 摩擦
332         fixDef.restitution = (restitution !== undefined ? restitution : 0.3); // 反発
333         fixDef.shape = new b2PolygonShape;
334         fixDef.shape.SetAsArray(vertexs, vertexs.length);
335         var bodyDef = new b2BodyDef;
336         bodyDef.type = type;
337         bodyDef.position.x = 0;
338         bodyDef.position.y = 0;
339         bodyDef.awake = (awake !== undefined ? awake : true);
340         bodyDef.userData = this;
341         this.body = world.CreateBody(bodyDef).CreateFixture(fixDef);
342         this.setDegugImage();
343         return this.body;
344     },
345     /**
346     * 円形の物理シミュレーション用Sprite生成.
347     * @param {Boolean} type 静的,動的,キネマティック
348     * @param {Number} density Spriteの密度.
349     * @param {Number} friction Spriteの摩擦.
350     * @param {Number} restitution Spriteの反発.
351     * @param {Boolean} awake Spriteが初めから物理演算を行うか.
352     */
353     createPhyCircle: function (type, density, friction, restitution, awake) {
354         var fixDef = new b2FixtureDef;
355         fixDef.density = (density !== undefined ? density : 1.0);             // 密度
356         fixDef.friction = (friction !== undefined ? friction : 0.5);          // 摩擦
357         fixDef.restitution = (restitution !== undefined ? restitution : 0.3); // 反発
358         fixDef.shape = new b2CircleShape(this.width / 2 / WORLD_SCALE);
359         var bodyDef = new b2BodyDef;
360         bodyDef.type = type;
361         bodyDef.position.x = 0;
362         bodyDef.position.y = 0;
363         bodyDef.awake = (awake !== undefined ? awake : true);
364         bodyDef.userData = this;
365         this.body = world.CreateBody(bodyDef).CreateFixture(fixDef);
366         this.setDegugImage();
367         return this.body;
368     },
369     /**
370     * デバッグ用のイメージをセット
371     */
372     setDegugImage: function () {
373         var surface = new Surface(this.width, this.height);
374         surface.context.strokeStyle = DebugDrawStrokeColor;
375         surface.context.fillStyle = DebugDrawFillColor;
376         surface.context.beginPath();
377         var shape = this.body.GetShape();
378         switch (shape.m_type) {
379             case b2Shape.e_circleShape:
380                 {
381                     var circle = shape;
382                     var r = circle.m_radius * WORLD_SCALE - 1;
383                     surface.context.arc(this.width / 2, this.height / 2, r, 0, Math.PI * 2, true);
384                     surface.context.moveTo(this.width / 2, this.height / 2);
385                     surface.context.lineTo(this.width - 1, this.height / 2);
386                 }
387                 break;
388             case b2Shape.e_polygonShape:
389                 {
390                     var poly = shape;
391                     var tV = poly.m_vertices[0];
392                     surface.context.moveTo(tV.x * WORLD_SCALE + this.width / 2, tV.y * WORLD_SCALE + this.height / 2);
393                     for (var i = 0; i < poly.m_vertexCount; i++) {
394                         var v = poly.m_vertices[i];
395                         surface.context.lineTo(v.x * WORLD_SCALE + this.width / 2, v.y * WORLD_SCALE + this.height / 2);
396                     }
397                     surface.context.lineTo(tV.x * WORLD_SCALE + this.width / 2, tV.y * WORLD_SCALE + this.height / 2);
398                 }
399                 break;
400             default:
401                 break;
402         }
403         surface.context.fill();
404         surface.context.stroke();
405         this.image = surface;
406         return surface;
407     },
408     /**
409     * Spriteのタイプ 静的(STATIC_SPRITE)か動的(DYNAMIC_SPRITE)かキネマティック(KINEMATIC_SPRITE)か
410     * @type {bool}
411     */
412     type: {
413         get: function () {
414             return this.body.m_body.GetType();
415         },
416         set: function (type) {
417             this.body.m_body.SetType(type);
418         }
419     },
420     /**
421     * Spriteのx座標.
422     * @type {Number}
423     */
424     x: {
425         get: function () {
426             return this.body.m_body.GetPosition().x * WORLD_SCALE - this.width / 2;
427         },
428         set: function (x) {
429             this._x = x;
430             x += this.width / 2;
431             this.body.m_body.SetPosition(new b2Vec2(x / WORLD_SCALE, this.body.m_body.GetPosition().y));
432             this._updateCoordinate();
433         }
434     },
435     /**
436     * Spriteのy座標.
437     * @type {Number}
438     */
439     y: {
440         get: function () {
441             return this.body.m_body.GetPosition().y * WORLD_SCALE - this.height / 2;
442         },
443         set: function (y) {
444             this._y = y;
445             y += this.height / 2;
446             this.body.m_body.SetPosition(new b2Vec2(this.body.m_body.GetPosition().x, y / WORLD_SCALE));
447             this._updateCoordinate();
448         }
449     },
450     /**
451     * Spriteの中心のx座標.
452     * @type {Number}
453     */
454     centerX: {
455         get: function () {
456             return this.x + this.width / 2;
457         },
458         set: function (x) {
459             this.x = x - this.width / 2;
460         }
461     },
462     /**
463     * Spriteの中心のy座標.
464     * @type {Number}
465     */
466     centerY: {
467         get: function () {
468             return this.y + this.height / 2;
469         },
470         set: function (y) {
471             this.y = y - this.height / 2;
472         }
473     },
474     /**
475     * Spriteの中心座標ベクトル.
476     * @type {b2Vec2}
477     */
478     position: {
479         get: function () {
480             var pos = this.body.m_body.GetPosition().Copy();
481             pos.Multiply(WORLD_SCALE);
482             return pos;
483         },
484         set: function (pos) {
485             this.centerX = pos.x;
486             this.centerY = pos.y;
487             this.body.m_body.SetPosition(new b2Vec2(pos.x / WORLD_SCALE, pos.y / WORLD_SCALE));
488         }
489     },
490     /**
491     * Spriteのx座標の速度(単位はpx/s).
492     * @type {Number}
493     */
494     vx: {
495         get: function () {
496             return this.body.m_body.GetLinearVelocity().x * WORLD_SCALE;
497         },
498         set: function (x) {
499             this.body.m_body.SetLinearVelocity(new b2Vec2(x / WORLD_SCALE, this.body.m_body.GetLinearVelocity().y));
500         }
501     },
502     /**
503     * Spriteのy座標の速度(単位はpx/s).
504     * @type {Number}
505     */
506     vy: {
507         get: function () {
508             return this.body.m_body.GetLinearVelocity().y * WORLD_SCALE;
509         },
510         set: function (y) {
511             this.body.m_body.SetLinearVelocity(new b2Vec2(this.body.m_body.GetLinearVelocity().x, y / WORLD_SCALE));
512         }
513     },
514     /**
515     * Spriteの速度(単位はpx/s).
516     * @type {b2Vec2}
517     */
518     velocity: {
519         get: function () {
520             var v = this.body.m_body.GetLinearVelocity().Copy();
521             v.Multiply(WORLD_SCALE);
522             return v;
523         },
524         set: function (v) {
525             this.body.m_body.SetLinearVelocity(new b2Vec2(v.x / WORLD_SCALE, v.y / WORLD_SCALE));
526         }
527     },
528     /**
529     * Spriteの角度 (度数法)..
530     * @type {Number}
531     */
532     angle: {
533         get: function () {
534             return this.body.m_body.GetAngle() * (180 / Math.PI);
535         },
536         set: function (angle) {
537             this.rotation = angle;
538             this.body.m_body.SetAngle(angle * (Math.PI / 180));
539         }
540     },
541     /**
542     * Spriteの角速度(単位はdeg/s).
543     * @type {b2Vec2}
544     */
545     angularVelocity: {
546         get: function () {
547             return this.body.m_body.GetAngularVelocity() * (180 / Math.PI);
548         },
549         set: function (omega) {
550             this.setAwake(true);
551             this.body.m_body.SetAngularVelocity(omega * (Math.PI / 180));
552         }
553     },
554     /**
555     * 継続的な力を加える
556     * @param {b2Vec2} force 加える力のベクトル
557     */
558     applyForce: function (force) {
559         this.setAwake(true);
560         this.body.m_body.ApplyForce(force, this.body.m_body.GetPosition());
561     },
562     /**
563     * 瞬間的な力を加える
564     * @param {b2Vec2} impulse 加える力のベクトル
565     */
566     applyImpulse: function (impulse) {
567         this.setAwake(true);
568         this.body.m_body.ApplyImpulse(impulse, this.body.m_body.GetPosition());
569     },
570     /**
571     * 継続的な回転力を与える
572     * @param {Number} torque 加える回転力
573     */
574     applyTorque: function (torque) {
575         this.setAwake(true);
576         this.body.m_body.ApplyTorque(torque);
577     },
578     /**
579     * 物理シミュレーションされているか
580     * 物体の動きが止まると処理コスト軽減のためsleep状態になる
581     * @type {Boolean}
582     */
583     sleep: {
584         get: function () {
585             return this.body.m_body.IsSleepingAllowed();
586         },
587         set: function (flag) {
588             this.setAwake(true);
589             this.body.m_body.SetSleepingAllowed(flag);
590         }
591     },
592     /**
593     * 物理シミュレーションされていない時、物理シミュレーションを行う(sleep時は動かなくなるので)
594     * @param {Boolean} flag 物理シミュレーションを行うかどうか
595     */
596     setAwake: function (flag) {
597         this.body.m_body.SetAwake(flag);
598     },
599     /**
600     * アクティブかどうか
601     * 物理シミュレーションが行われて、他の物体に干渉できるか
602     * @type {Boolean}
603     */
604     active: {
605         get: function () {
606             return this.body.m_body.IsActive();
607         },
608         set: function (flag) {
609             this.body.m_body.SetActive(flag);
610         }
611     },
612     /**
613     * 表示/非表示(物理シミュレーションも止まる)
614     * @type {Boolean}
615     */
616     visible: {
617         get: function () {
618             return this.active;
619         },
620         set: function (visible) {
621             if (this._visible == visible) {
622                 this._style.display = 'block';
623             } else {
624                 this._style.display = 'none';
625             }
626             this.active = visible;
627         }
628     },
629     /**
630     * 静的オブジェクトかどうか
631     * @return {Boolean}
632     */
633     isStatic: function () {
634         return (this.type == STATIC_SPRITE);
635     },
636     /**
637     * 動的オブジェクトかどうか
638     * @return {Boolean}
639     */
640     isDynamic: function () {
641         return (this.type == DYNAMIC_SPRITE);
642     },
643     /**
644     * キネマティックオブジェクトかどうか
645     * @return {Boolean}
646     */
647     isKinematic: function () {
648         return (this.type == KINEMATIC_SPRITE);
649     },
650     /**
651     * 衝突判定
652     * @example
653     *   //bearに当たったSpriteを消す
654     *   bear.contact(function (sprite) {
655     *      sprite.destroy(); 
656     *   });
657     * 
658     * @param {function(sprite:enchant.PhySprite)} [func] ぶつかったSpriteを引数とする関数
659     */
660     contact: function (func) {
661         var c = this.body.m_body.m_contactList;
662         if (c) {
663             for (var contact = c.contact; contact; contact = contact.m_next) {
664                 var pos1 = contact.m_fixtureA.m_body.GetPosition().Copy();
665                 pos1.Subtract(contact.m_fixtureB.m_body.GetPosition());
666                 pos1.Multiply(WORLD_SCALE);
667                 var r1 = (contact.m_fixtureA.m_body.m_userData.width + contact.m_fixtureB.m_body.m_userData.width) / 1.5;
668                 var r2 = (contact.m_fixtureA.m_body.m_userData.height + contact.m_fixtureB.m_body.m_userData.height) / 1.5;
669                 if (Math.abs(pos1.x) <= r1 && Math.abs(pos1.y) <= r2) {
670                     //片方が自分ならもう片方をぶつかった相手として処理する
671                     if (this.body.m_body == contact.m_fixtureA.m_body)
672                         func(contact.m_fixtureB.m_body.m_userData);
673                     else if (this.body.m_body == contact.m_fixtureB.m_body)
674                         func(contact.m_fixtureA.m_body.m_userData);
675                 }
676             }
677         }
678     },
679     /**
680     * 物体の削除
681     * removeChildではなくこちらでSpriteを取り除く
682     */
683     destroy: function () {
684         if (this.scene !== null) {
685             world.DestroyBody(this.body.m_body);
686             this.body.Destroy();
687             this.scene.removeChild(this);
688         }
689     },
690     /**
691     * bodyの取得
692     * Box2Dの処理を各自行いたい時に取得する
693     */
694     getBody: function () {
695         return this.body;
696     }
697 
698 });
699 
700 /**
701 * @scope enchant.PhyBoxSprite.prototype
702 */
703 enchant.PhyBoxSprite = enchant.Class.create(enchant.PhySprite, {
704     /**
705     * 四角形の物理シミュレーション用Sprite
706     * @example
707     *   var bear = new PhyBoxSprite(32, 32, DYNAMIC_SPRITE, 1.0, 0.5, 0.3, true);
708     *   bear.image = game.assets['chara1.gif'];
709     * 
710     * @param {Number} [width] Spriteの横幅.
711     * @param {Number} [height] Spriteの高さ.
712     * @param {Boolean} [type] 静的,動的,キネマティック
713     * @param {Number} [density] Spriteの密度.
714     * @param {Number} [friction] Spriteの摩擦.
715     * @param {Number} [restitution] Spriteの反発.
716     * @param {Boolean}   [awake] Spriteが初めから物理演算を行うか.
717     * @constructs
718     * @extends enchant.PhySprite
719     */
720     initialize: function (width, height, type, density, friction, restitution, awake) {
721         enchant.PhySprite.call(this, width, height);
722 
723         //物理オブジェクトの生成
724         this.createPhyBox(type, density, friction, restitution, awake);
725     }
726 });
727 
728 
729 /**
730 * @scope enchant.PhyCircleSprite.prototype
731 */
732 enchant.PhyCircleSprite = enchant.Class.create(enchant.PhySprite, {
733     /**
734     * 円の物理シミュレーション用Sprite
735     * @example
736     *   var bear = new PhyCircleSprite(16, DYNAMIC_SPRITE, 1.0, 0.5, 0.3, true);
737     *   bear.image = game.assets['chara1.gif'];
738     * 
739     * @param {Number} [radius] Spriteの半径.
740     * @param {Boolean} [type] 静的,動的,キネマティック
741     * @param {Number} [density] Spriteの密度.
742     * @param {Number} [friction] Spriteの摩擦.
743     * @param {Number} [restitution] Spriteの反発.
744     * @param {Boolean}   [awake] Spriteが初めから物理演算を行うか.
745     * @constructs
746     * @extends enchant.PhySprite
747     */
748     initialize: function (radius, type, density, friction, restitution, awake) {
749         enchant.PhySprite.call(this, radius * 2, radius * 2);
750 
751         //物理オブジェクトの生成
752         this.createPhyCircle(type, density, friction, restitution, awake);
753     }
754 });
755 
756 /**
757 * @scope enchant.PhyPolygonSprite.prototype
758 */
759 enchant.PhyPolygonSprite = enchant.Class.create(enchant.PhySprite, {
760     /**
761     * 多角形の物理シミュレーション用Sprite
762     * @example
763     * var vertexCount = 5;
764     * var radius = 20;
765     * var vertexs = new Array();
766     * for (var i = 0; i < vertexCount; i++) {
767     *     vertexs[i] = new b2Vec2(radius * Math.cos(2 * Math.PI / vertexCount * i), radius * Math.sin(2 * Math.PI / vertexCount * i));
768     * }
769     * var phyPolygonSprite = new PhyPolygonSprite(radius * 2, radius * 2,vertexs, DYNAMIC_SPRITE, 1.0, 0.1, 0.2, true);
770     * @param {Number} [width] Spriteの横幅.
771     * @param {Number} [height] Spriteの高さ.
772     * @param {b2Vec2[]} vertexs 多角形の頂点配列
773     * @param {Boolean} [type] 静的,動的,キネマティック
774     * @param {Number} [density] Spriteの密度.
775     * @param {Number} [friction] Spriteの摩擦.
776     * @param {Number} [restitution] Spriteの反発.
777     * @param {Boolean}   [awake] Spriteが初めから物理演算を行うか.
778     * @constructs
779     * @extends enchant.PhySprite
780     */
781     initialize: function (width, height, vertexs, type, density, friction, restitution, awake) {
782         enchant.PhySprite.call(this, width, height);
783         //物理オブジェクトの生成
784         this.createPhyPolygon(vertexs, type, density, friction, restitution, awake);
785     }
786 });
787 
788 
789 /**
790 * @scope enchant.BaseJoint.prototype
791 */
792 enchant.BaseJoint = enchant.Class.create({
793     /**
794     * ジョイントの親クラス
795     * @param {enchant.PhySprite} [sprite1] 繋げるスプライト1
796     * @param {enchant.PhySprite} [sprite2] 繋げるスプライト2
797     * @constructs
798     */
799     initialize: function (sprite1, sprite2) {
800         this.joint = null;
801         /**
802         * ジョイントのアンカー1.
803         * @type {PhySprite}
804         */
805         this.sprite1 = sprite1;
806         /**
807         * ジョイントのアンカー2.
808         * @type {PhySprite}
809         */
810         this.sprite2 = sprite2;
811     },
812     /**
813     * ジョイントの削除
814     */
815     destroy: function () {
816         if (this.joint !== null) {
817             world.DestroyJoint(this.joint);
818             this.joint = null;
819         }
820     }
821 });
822 
823 /**
824 * @scope enchant.PhyDistanceJoint.prototype
825 */
826 enchant.PhyDistanceJoint = enchant.Class.create(enchant.BaseJoint, {
827     /**
828     * 距離ジョイント
829     * @example
830     * //軸
831     * var axis = new PhyCircleSprite(8, STATIC_SPRITE);
832     * axis.position = { x: 160, y: 160 };
833     * game.rootScene.addChild(axis); // シーンに追加
834     * //ボール生成
835     * var ball = new PhyCircleSprite(8, DYNAMIC_SPRITE);
836     * ball.position = { x: 100, y: 250 };
837     * game.rootScene.addChild(ball); // シーンに追加
838     * //距離ジョイント
839     * var joint = new PhyDistanceJoint(axis, ball);
840     * @param {enchant.PhySprite} [sprite1] 繋げるスプライト1
841     * @param {enchant.PhySprite} [sprite2] 繋げるスプライト2
842     * @constructs
843     * @extends enchant.BaseJoint
844     */
845     initialize: function (sprite1, sprite2) {
846         enchant.BaseJoint.call(this, sprite1, sprite2);
847 
848         var jointDef = new b2DistanceJointDef();
849         jointDef.Initialize(sprite1.body.m_body, sprite2.body.m_body, sprite1.body.m_body.GetPosition(), sprite2.body.m_body.GetPosition());
850         this.joint = world.CreateJoint(jointDef);
851     },
852     /**
853     * ジョイントの距離
854     * @type {Number}
855     */
856     length: {
857         get: function () {
858             return this.joint.m_length * WORLD_SCALE;
859         },
860         set: function (length) {
861             this.joint.m_length = length / WORLD_SCALE;
862         }
863     },
864     /**
865     * 減衰比. 0 =減衰なし、1 =臨界減衰。
866     * @type {Number}
867     */
868     dampingRatio: {
869         get: function () {
870             return this.joint.m_dampingRatio;
871         },
872         set: function (dampingRatio) {
873             this.joint.m_dampingRatio = dampingRatio;
874         }
875     },
876     /**
877     * 応答速度. 
878     * @type {Number}
879     */
880     frequencyHz: {
881         get: function () {
882             return this.joint.m_frequencyHz;
883         },
884         set: function (frequencyHz) {
885             this.joint.m_frequencyHz = frequencyHz;
886         }
887     }
888 });
889 
890 
891 /**
892 * @scope enchant.PhyRevoluteJoint.prototype
893 */
894 enchant.PhyRevoluteJoint = enchant.Class.create(enchant.BaseJoint, {
895     /**
896     * 物体と物体のモーター付きジョイント 
897     * @example
898     * //軸
899     * var axis = new PhyCircleSprite(8, STATIC_SPRITE);
900     * axis.position = { x: 160, y: 160 };
901     * game.rootScene.addChild(axis); // シーンに追加
902     * //ボール生成
903     * var ball = new PhyCircleSprite(8, DYNAMIC_SPRITE);
904     * ball.position = { x: 100, y: 250 };
905     * game.rootScene.addChild(ball); // シーンに追加
906     * //距離ジョイント
907     * var joint = new PhyRevoluteJoint(axis, ball);
908     * joint.enableMotor = true;
909     * joint.maxMotorTorque = 100;
910     * joint.motorSpeed = 90;
911     * @param {enchant.PhySprite} [axis] 軸となるスプライト
912     * @param {enchant.PhySprite} [sprite] 繋げるスプライト
913     * @constructs
914     * @extends enchant.BaseJoint
915     */
916     initialize: function (axis, sprite) {
917         enchant.BaseJoint.call(this, axis, sprite);
918 
919         var joint_def = new b2RevoluteJointDef();
920         joint_def.Initialize(sprite.body.m_body, axis.body.m_body, axis.body.m_body.GetWorldCenter());
921 
922         //create and save the joint
923         this.joint = world.CreateJoint(joint_def);
924     },
925     /**
926     * モータの回転速度(deg/s)
927     * @type {Number}
928     */
929     motorSpeed: {
930         get: function () {
931             return this.joint.m_motorSpeed * (180 / Math.PI);
932         },
933         set: function (speed) {
934             this.joint.m_motorSpeed = speed * (Math.PI / 180);
935         }
936     },
937     /**
938     * モータを有効化/無効化
939     * @type {Boolean}
940     */
941     enableMotor: {
942         get: function () {
943             return this.joint.m_enableMotor;
944         },
945         set: function (enableMotor) {
946             this.joint.m_enableMotor = enableMotor;
947         }
948     },
949     /**
950     * トルクの最大値
951     * @type {Number}
952     */
953     maxMotorTorque: {
954         get: function () {
955             return this.joint.m_maxMotorTorque;
956         },
957         set: function (maxMotorTorque) {
958             this.joint.m_maxMotorTorque = maxMotorTorque;
959         }
960     },
961     /**
962     * 限界の有効化/無効化
963     * @type {Boolean}
964     */
965     enableLimit: {
966         get: function () {
967             return this.joint.m_enableLimit;
968         },
969         set: function (enableLimit) {
970             this.joint.m_enableLimit = enableLimit;
971         }
972     },
973     /**
974     * 最低角度
975     * @type {Number}
976     */
977     lowerAngle: {
978         get: function () {
979             return this.joint.m_lowerAngle * (180 / Math.PI);
980         },
981         set: function (lowerAngle) {
982             this.joint.m_lowerAngle = lowerAngle * (Math.PI / 180);
983         }
984     },
985     /**
986     * 最高角度
987     * @type {Number}
988     */
989     upperAngle: {
990         get: function () {
991             return this.joint.m_upperAngle * (180 / Math.PI);
992         },
993         set: function (upperAngle) {
994             this.joint.m_upperAngle = upperAngle * (Math.PI / 180);
995         }
996     },
997     /**
998     * 最高/最低角度の設定
999     * @param {Number} [lower] 最低角度
1000     * @param {Number} [upper] 最高角度
1001     */
1002     setLimits: function (lower, upper) {
1003         this.joint.SetLimits(lower * (Math.PI / 180), upper * (Math.PI / 180));
1004     },
1005     getJointAngle: function () {
1006         return this.joint.GetJointAngle() * (180 / Math.PI);
1007     }
1008 });
1009 
1010 
1011 /**
1012 * @scope enchant.PhyPulleyJoint.prototype
1013 */
1014 enchant.PhyPulleyJoint = enchant.Class.create(enchant.BaseJoint, {
1015     /**
1016     * 滑車ジョイント
1017     * @example
1018     * var ball1 = new PhyCircleSprite(8, DYNAMIC_SPRITE);
1019     * ball1.position = { x: 80, y: 160 };
1020     * var ball2 = new PhyCircleSprite(8, DYNAMIC_SPRITE);
1021     * ball2.position = { x: 240, y: 160 };
1022     * //滑車ジョイント
1023     * var pulleyJoint = new PhyPulleyJoint(ball1, ball2, new b2Vec2(80, 100), new b2Vec2(240, 100), 1);
1024     * @param {enchant.PhySprite} [sprite1] 繋げるスプライト1
1025     * @param {enchant.PhySprite} [sprite2] 繋げるスプライト2
1026     * @param {b2Vec2} [anchor1] アンカー1の位置
1027     * @param {b2Vec2} [anchor2] アンカー2の位置
1028     * @param {Number} [ratio] 左右のバランス
1029     * @constructs
1030     * @extends enchant.BaseJoint
1031     */
1032     initialize: function (sprite1, sprite2, anchor1, anchor2, ratio) {
1033         enchant.BaseJoint.call(this, sprite1, sprite2);
1034 
1035         anchor1.Multiply(1 / WORLD_SCALE);
1036         anchor2.Multiply(1 / WORLD_SCALE);
1037 
1038         var jointDef = new b2PulleyJointDef();
1039         jointDef.Initialize(sprite1.body.m_body, sprite2.body.m_body, anchor1, anchor2, sprite1.body.m_body.GetPosition(), sprite2.body.m_body.GetPosition(), ratio);
1040 
1041         this.joint = world.CreateJoint(jointDef);
1042     }
1043 });
1044 
1045 /**
1046 * @scope enchant.PhyPrismaticJoint.prototype
1047 */
1048 enchant.PhyPrismaticJoint = enchant.Class.create(enchant.BaseJoint, {
1049     /**
1050     * スライドジョイント    
1051     * @example
1052     * var box = new PhyBoxSprite(16, 8, DYNAMIC_SPRITE, 1.0, 0.5, 0.2, true);
1053     * box.position = { x: game.width * 2 / 3, y: game.height / 2 };
1054     * var prismaticAxis = new b2Vec2(1.0, 0);   //x軸にスライドを設定(右が正の値)
1055     * //スライドジョイント
1056     * var prismaticJoint = new PhyPrismaticJoint(box, prismaticAxis);
1057     * //スライドオブジェクトにモーター機能を持たせる場合
1058     * //prismaticJoint.enableMotor = true;      //モータの有効化
1059     * //prismaticJoint.maxMotorForce = 100.0;   //モータの最大力を設定
1060     * //prismaticJoint.motorSpeed = 50;         //モータの速度を設定
1061     * @param {enchant.PhySprite} [sprite1] スライドさせるスプライト
1062     * @param {b2Vec2} [axis] 軸
1063     * @constructs
1064     * @extends enchant.BaseJoint
1065     */
1066     initialize: function (sprite1, axis) {
1067         enchant.BaseJoint.call(this, sprite1, null);
1068 
1069         var jointDef = new b2PrismaticJointDef();
1070         jointDef.Initialize(world.GetGroundBody(), sprite1.body.m_body, sprite1.body.m_body.GetPosition(), axis);
1071 
1072         this.joint = world.CreateJoint(jointDef);
1073     },
1074     /**
1075     * モータを有効化/無効化
1076     * @type {Boolean}
1077     */
1078     enableMotor: {
1079         get: function () {
1080             return this.joint.m_enableMotor;
1081         },
1082         set: function (enableMotor) {
1083             this.joint.m_enableMotor = enableMotor;
1084         }
1085     },
1086     /**
1087     * 限界の有効化/無効化
1088     * @type {Boolean}
1089     */
1090     enableLimit: {
1091         get: function () {
1092             return this.joint.m_enableLimit;
1093         },
1094         set: function (enableLimit) {
1095             this.joint.m_enableLimit = enableLimit;
1096         }
1097     },
1098     /**
1099     * 下ジョイント制限
1100     * @type {Number}
1101     */
1102     lowerTranslation: {
1103         get: function () {
1104             return this.joint.m_lowerTranslation * WORLD_SCALE;
1105         },
1106         set: function (lowerTranslation) {
1107             this.joint.m_lowerTranslation = lowerTranslation / WORLD_SCALE;
1108         }
1109     },
1110     /**
1111     * 上ジョイント制限
1112     * @type {Number}
1113     */
1114     upperTranslation: {
1115         get: function () {
1116             return this.joint.m_upperTranslation * WORLD_SCALE;
1117         },
1118         set: function (upperTranslation) {
1119             this.joint.m_upperTranslation = upperTranslation / WORLD_SCALE;
1120         }
1121     },
1122     /**
1123     * ジョイント制限の設定
1124     * @param {Number} [lower] 下ジョイント
1125     * @param {Number} [upper] 上ジョイント
1126     */
1127     setLimits: function (lower, upper) {
1128         this.lowerTranslation = lower;
1129         this.upperTranslation = upper;
1130     },
1131     /**
1132     * モーターの力の最大値
1133     * @type {Number}
1134     */
1135     maxMotorForce: {
1136         get: function () {
1137             return this.joint.maxMotorForce;
1138         },
1139         set: function (maxMotorForce) {
1140             this.joint.m_maxMotorForce = maxMotorForce;
1141         }
1142     },
1143     /**
1144     * モーターのスピード
1145     * @type {Number}
1146     */
1147     motorSpeed: {
1148         get: function () {
1149             return this.joint.m_motorSpeed * WORLD_SCALE;
1150         },
1151         set: function (motorSpeed) {
1152             this.joint.m_motorSpeed = motorSpeed / WORLD_SCALE;
1153         }
1154     }
1155 });
1156 
1157 
1158 //実装する予定は未定
1159 //enchant.PhyGearJoint = enchant.Class.create(enchant.BaseJoint, {
1160 //    /**
1161 //    * 歯車ジョイント
1162 //    * @param {enchant.PhySprite} [sprite1] 繋げるスプライト1
1163 //    * @param {enchant.PhySprite} [sprite2] 繋げるスプライト2
1164 //    * @param {Number} [ratio] 左右のバランス
1165 //    * @constructs
1166 //    * @extends enchant.BaseJoint
1167 //    */
1168 //    initialize: function (sprite1, sprite2, ratio) {
1169 //        enchant.BaseJoint.call(this, sprite1, sprite2);
1170 //        var ground = world.GetGroundBody();
1171 //        var jointDef = new b2GearJointDef();
1172 //        jointDef.body1 = sprite1.body.m_body;
1173 //        jointDef.body2 = sprite2.body.m_body;
1174 //        jointDef.joint1 = ;
1175 //        jointDef.joint2 = ;
1176 //        jointDef.ratio = ratio;
1177 //        this.joint = world.CreateJoint(jointDef);
1178 //    }
1179 //});
1180