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