1 /** 2 * @fileOverview 3 * PhySprite.enchant.js v1.30 4 * 5 * The MIT License 6 * 7 * Copyright (c) 2012/01/26 kassy708 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 * THE SOFTWARE. 26 * 27 * 物理演算用のSprite 28 * 29 * @author kassy708 http://twitter.com/kassy708 30 * 31 * このプラグインではBox2dWeb.jsを用いています。 32 * 最新のBox2dWeb.jsは下記アドレスからダウンロードしてください。 33 * http://www.gphysics.com 34 */ 35 36 37 if (!Box2D)throw new Error("box2d.enchant.js must be loaded after Box2dWeb.js"); 38 39 /* export */ 40 var b2Vec2 = Box2D.Common.Math.b2Vec2 41 , b2AABB = Box2D.Collision.b2AABB 42 , b2BodyDef = Box2D.Dynamics.b2BodyDef 43 , b2Body = Box2D.Dynamics.b2Body 44 , b2FixtureDef = Box2D.Dynamics.b2FixtureDef 45 , b2Fixture = Box2D.Dynamics.b2Fixture 46 , b2World = Box2D.Dynamics.b2World 47 , b2MassData = Box2D.Collision.Shapes.b2MassData 48 , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape 49 , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape 50 , b2DebugDraw = Box2D.Dynamics.b2DebugDraw 51 , b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef; 52 53 /** 54 * @type {Object} 55 */ 56 enchant.box2d = {}; 57 58 (function() { 59 var WORLD_SCALE = 32; 60 var world; 61 62 /** 63 * Spriteの種類(スタティック) 64 * @type {Number} 65 */ 66 enchant.box2d.STATIC_SPRITE = 0; 67 /** 68 * Spriteの種類(ダイナミック) 69 * @type {Number} 70 */ 71 enchant.box2d.DYNAMIC_SPRITE = 2; 72 73 /** 74 * @scope enchant.box2d.PhysicsWorld.prototype 75 */ 76 enchant.box2d.PhysicsWorld = enchant.Class.create({ 77 /** 78 * 物理シミュレーションを行う世界のクラス 79 * @example 80 * //y軸方向へ重力加速度9.8m/s^2 81 * var physicsWorld = new PhysicsWorld(0, 9.8); 82 * //無重力 83 * var physicsWorld = new PhysicsWorld(0, 0); 84 * 85 * @param {Number} [gravityX] x軸方向への引力. 86 * @param {Number} [gravityY] y軸方向への引力. 87 * @constructs 88 */ 89 initialize: function(gravityX, gravityY) { 90 /** 91 * 物理シミュレーションの精度 92 * @type {Nunber} 93 */ 94 this.iterations = 10; 95 world = new b2World( 96 new b2Vec2(gravityX, gravityY) //gravity 97 , true //allow sleep 98 ); 99 }, 100 /** 101 * 物理シミュレーション内の時間を進める 102 * @param {b2Vec2} [pos] Spriteの座標. 103 */ 104 step: function(fps) { 105 world.Step(1 / fps, this.iterations, this.iterations); 106 }, 107 /** 108 * 物体の当たり判定 109 * @example 110 * //ぶつかった2つのSpriteを消す 111 * physicsWorld.contact(function (sprite1, sprite2) { 112 * sprite1.destroy(); 113 * sprite2.destroy(); 114 * }); 115 * 116 * @param {function(sprite1:enchant.box2d.PhySprite,sprite2:enchant.box2d.PhySprite)} [func] 当たり判定時の処理 117 */ 118 contact: function(func) { 119 var c = world.m_contactList; 120 if (c) { 121 for (var contact = c; contact; contact = contact.m_next) { 122 var pos1 = contact.m_fixtureA.m_body.GetPosition().Copy(); 123 pos1.Subtract(contact.m_fixtureB.m_body.GetPosition()); 124 pos1.Multiply(WORLD_SCALE); 125 var r1 = (contact.m_fixtureA.m_body.m_userData.width + contact.m_fixtureB.m_body.m_userData.width) / 2; 126 var r2 = (contact.m_fixtureA.m_body.m_userData.height + contact.m_fixtureB.m_body.m_userData.height) / 2; 127 if (Math.abs(pos1.x) <= r1 && Math.abs(pos1.y) <= r2) { 128 func(contact.m_fixtureA.m_body.m_userData, contact.m_fixtureB.m_body.m_userData); 129 } 130 } 131 } 132 } 133 }); 134 135 136 /** 137 * @scope enchant.box2d.PhySprite.prototype 138 */ 139 enchant.box2d.PhySprite = enchant.Class.create(enchant.Sprite, { 140 /** 141 * 画像表示機能を持った物理シミュレーションクラス. 142 * @param {Number} [width] Spriteの横幅. 143 * @param {Number} [height] Spriteの高さ. 144 * @constructs 145 * @extends enchant.Sprite 146 */ 147 initialize: function(width, height) { 148 this.body; 149 /** 150 * 静的オブジェクトか動的オブジェクトか 151 */ 152 this.staticOrDynamic; 153 enchant.Sprite.call(this, width, height); 154 155 var time = 0; 156 this.addEventListener(enchant.Event.ENTER_FRAME, function(e) { 157 this.x = this.x; 158 this.y = this.y; 159 this.rotation = this.angle; 160 time++; 161 time = time % 2; 162 }); 163 }, 164 /** 165 * 四角形の物理シミュレーション用Sprite生成. 166 * @param {Boolean} staticOrDynamic 静止するか動くか. 167 * @param {Number} density Spriteの密度. 168 * @param {Number} friction Spriteの摩擦. 169 * @param {Number} restitution Spriteの反発. 170 * @param {Boolean} isSleeping Spriteが初めから物理演算を行うか. 171 */ 172 createPhyBox: function(staticOrDynamic, density, friction, restitution, awake) { 173 this.staticOrDynamic = staticOrDynamic; 174 var fixDef = new b2FixtureDef; 175 fixDef.density = (density != null ? density : 1.0); // 密度 176 fixDef.friction = (friction != null ? friction : 0.5); // 摩擦 177 fixDef.restitution = (restitution != null ? restitution : 0.3); // 反発 178 fixDef.shape = new b2PolygonShape; 179 fixDef.shape.SetAsBox(this.width / 2 / WORLD_SCALE, this.height / 2 / WORLD_SCALE); 180 var bodyDef = new b2BodyDef; 181 bodyDef.type = staticOrDynamic; 182 bodyDef.position.x = 0; 183 bodyDef.position.y = 0; 184 bodyDef.awake = (awake != null ? awake : true); 185 bodyDef.userData = this; 186 return world.CreateBody(bodyDef).CreateFixture(fixDef); 187 }, 188 /** 189 * 円形の物理シミュレーション用Sprite生成. 190 * @param {Boolean} staticOrDynamic 静止するか動くか. 191 * @param {Number} density Spriteの密度. 192 * @param {Number} friction Spriteの摩擦. 193 * @param {Number} restitution Spriteの反発. 194 * @param {Boolean} isSleeping Spriteが初めから物理演算を行うか. 195 */ 196 createPhyCircle: function(staticOrDynamic, density, friction, restitution, awake) { 197 this.staticOrDynamic = staticOrDynamic; 198 var fixDef = new b2FixtureDef; 199 fixDef.density = (density != null ? density : 1.0); // 密度 200 fixDef.friction = (friction != null ? friction : 0.5); // 摩擦 201 fixDef.restitution = (restitution != null ? restitution : 0.3); // 反発 202 fixDef.shape = new b2CircleShape(this.width / 2 / WORLD_SCALE); 203 var bodyDef = new b2BodyDef; 204 bodyDef.type = staticOrDynamic; 205 bodyDef.position.x = 0; 206 bodyDef.position.y = 0; 207 bodyDef.awake = (awake != null ? awake : true); 208 bodyDef.userData = this; 209 return world.CreateBody(bodyDef).CreateFixture(fixDef); 210 }, 211 /** 212 * Spriteのタイプ 静的(STATIC_SPRITE)か動的(DYNAMIC_SPRITE)か 213 * @type {bool} 214 */ 215 type: { 216 get: function() { 217 if (this.body.m_body.GetType() == b2Body.b2_staticBody) 218 return enchant.box2d.STATIC_SPRITE; 219 return enchant.box2d.DYNAMIC_SPRITE; 220 }, 221 set: function(staticOrDynamic) { 222 this.staticOrDynamic = staticOrDynamic; 223 this.body.m_body.SetType(staticOrDynamic); 224 } 225 }, 226 /** 227 * Spriteのx座標. 228 * @type {Number} 229 */ 230 x: { 231 get: function() { 232 return this.body.m_body.GetPosition().x * WORLD_SCALE - this.width / 2; 233 }, 234 set: function(x) { 235 this._x = x; 236 x += this.width / 2; 237 this.body.m_body.SetPosition(new b2Vec2(x / WORLD_SCALE, this.body.m_body.GetPosition().y)); 238 this._dirty = true; 239 } 240 }, 241 /** 242 * Spriteのy座標. 243 * @type {Number} 244 */ 245 y: { 246 get: function() { 247 return this.body.m_body.GetPosition().y * WORLD_SCALE - this.height / 2; 248 }, 249 set: function(y) { 250 this._y = y; 251 y += this.height / 2; 252 this.body.m_body.SetPosition(new b2Vec2(this.body.m_body.GetPosition().x, y / WORLD_SCALE)); 253 this._dirty = true; 254 } 255 }, 256 /** 257 * Spriteの中心のx座標. 258 * @type {Number} 259 */ 260 centerX: { 261 get: function() { 262 return this.x + this.width / 2; 263 }, 264 set: function(x) { 265 this.x = x - this.width / 2; 266 } 267 }, 268 /** 269 * Spriteの中心のy座標. 270 * @type {Number} 271 */ 272 centerY: { 273 get: function() { 274 return this.y + this.height / 2; 275 }, 276 set: function(y) { 277 this.y = y - this.height / 2; 278 } 279 }, 280 /** 281 * Spriteの中心座標ベクトル. 282 * @type {b2Vec2} 283 */ 284 position: { 285 get: function() { 286 var pos = this.body.m_body.GetPosition().Copy(); 287 pos.Multiply(WORLD_SCALE); 288 return pos; 289 }, 290 set: function(pos) { 291 this.centerX = pos.x; 292 this.centerY = pos.y; 293 this.body.m_body.SetPosition(new b2Vec2(pos.x / WORLD_SCALE, pos.y / WORLD_SCALE)); 294 } 295 }, 296 /** 297 * Spriteのx座標の速度(単位はpx/s). 298 * @type {Number} 299 */ 300 vx: { 301 get: function() { 302 return this.body.m_body.GetLinearVelocity().x * WORLD_SCALE; 303 }, 304 set: function(x) { 305 this.body.m_body.SetLinearVelocity(new b2Vec2(x / WORLD_SCALE, this.body.m_body.GetLinearVelocity().y)); 306 } 307 }, 308 /** 309 * Spriteのy座標の速度(単位はpx/s). 310 * @type {Number} 311 */ 312 vy: { 313 get: function() { 314 return this.body.m_body.GetLinearVelocity().y * WORLD_SCALE; 315 }, 316 set: function(y) { 317 this.body.m_body.SetLinearVelocity(new b2Vec2(this.body.m_body.GetLinearVelocity().x, y / WORLD_SCALE)); 318 } 319 }, 320 /** 321 * Spriteの速度(単位はpx/s). 322 * @type {b2Vec2} 323 */ 324 velocity: { 325 get: function() { 326 var v = this.body.m_body.GetLinearVelocity().Copy(); 327 v.Multiply(WORLD_SCALE); 328 return v; 329 }, 330 set: function(v) { 331 this.body.m_body.SetLinearVelocity(new b2Vec2(v.x / WORLD_SCALE, v.y / WORLD_SCALE)); 332 } 333 }, 334 /** 335 * Spriteの角度 (度数法).. 336 * @type {Number} 337 */ 338 angle: { 339 get: function() { 340 return this.body.m_body.GetAngle() * (180 / Math.PI); 341 }, 342 set: function(angle) { 343 this.rotation = angle; 344 this.body.m_body.SetAngle(angle * (Math.PI / 180)); 345 } 346 }, 347 /** 348 * Spriteの角速度(単位はdeg/s). 349 * @type {b2Vec2} 350 */ 351 angularVelocity: { 352 get: function() { 353 return this.body.m_body.GetAngularVelocity() * (180 / Math.PI); 354 }, 355 set: function(omega) { 356 this.setAwake(true); 357 this.body.m_body.SetAngularVelocity(omega * (Math.PI / 180)); 358 } 359 }, 360 /** 361 * 継続的な力を加える 362 * @param {b2Vec2} force 加える力のベクトル 363 */ 364 applyForce: function(force) { 365 this.setAwake(true); 366 this.body.m_body.ApplyForce(force, this.body.m_body.GetPosition()); 367 }, 368 /** 369 * 瞬間的な力を加える 370 * @param {b2Vec2} impulse 加える力のベクトル 371 */ 372 applyImpulse: function(impulse) { 373 this.setAwake(true); 374 this.body.m_body.ApplyImpulse(impulse, this.body.m_body.GetPosition()); 375 }, 376 /** 377 * 継続的な回転力を与える 378 * @param {Number} torque 加える回転力 379 */ 380 applyTorque: function(torque) { 381 this.setAwake(true); 382 this.body.m_body.ApplyTorque(torque); 383 }, 384 /** 385 * 物理シミュレーションされているか 386 * @type {Boolean} 387 */ 388 sleep: { 389 get: function() { 390 return this.body.m_body.IsSleepingAllowed(); 391 }, 392 set: function(flag) { 393 this.setAwake(true); 394 this.body.m_body.SetSleepingAllowed(flag); 395 } 396 }, 397 /** 398 * 物理シミュレーションされていない時、物理シミュレーションを行う(sleep時は動かなくなるので) 399 * @param {Boolean} flag 物理シミュレーションを行うかどうか 400 */ 401 setAwake: function(flag) { 402 this.body.m_body.SetAwake(flag); 403 }, 404 /** 405 * 衝突判定 406 * @example 407 * //bearに当たったSpriteを消す 408 * bear.contact(function (sprite) { 409 * sprite.destroy(); 410 * }); 411 * 412 * @param {function(sprite:enchant.box2d.PhySprite)} [func] ぶつかったSpriteを引数とする関数 413 */ 414 contact: function(func) { 415 var c = this.body.m_body.m_contactList; 416 if (c) { 417 for (var contact = c.contact; contact; contact = contact.m_next) { 418 var pos1 = contact.m_fixtureA.m_body.GetPosition().Copy(); 419 pos1.Subtract(contact.m_fixtureB.m_body.GetPosition()); 420 pos1.Multiply(WORLD_SCALE); 421 var r1 = (contact.m_fixtureA.m_body.m_userData.width + contact.m_fixtureB.m_body.m_userData.width) / 1.5; 422 var r2 = (contact.m_fixtureA.m_body.m_userData.height + contact.m_fixtureB.m_body.m_userData.height) / 1.5; 423 if (Math.abs(pos1.x) <= r1 && Math.abs(pos1.y) <= r2) { 424 //片方が自分ならもう片方をぶつかった相手として処理する 425 if (this.body.m_body == contact.m_fixtureA.m_body) 426 func(contact.m_fixtureB.m_body.m_userData); 427 else if (this.body.m_body == contact.m_fixtureB.m_body) 428 func(contact.m_fixtureA.m_body.m_userData); 429 } 430 } 431 } 432 }, 433 /** 434 * 物体の削除 435 * removeChildではなくこちらでSpriteを取り除く 436 */ 437 destroy: function() { 438 world.DestroyBody(this.body.m_body); 439 this.body.Destroy(); 440 if (this.parentNode !== null) { 441 this.parentNode.removeChild(this); 442 } 443 } 444 445 }); 446 447 /** 448 * @scope enchant.PhyBoxSprite.prototype 449 */ 450 enchant.box2d.PhyBoxSprite = enchant.Class.create(enchant.box2d.PhySprite, { 451 /** 452 * 四角形の物理シミュレーション用Sprite 453 * @example 454 * var bear = new PhyBoxSprite(32, 32, enchant.box2d.DYNAMIC_SPRITE, 1.0, 0.5, 0.3, true); 455 * bear.image = core.assets['chara1.gif']; 456 * 457 * @param {Number} [width] Spriteの横幅. 458 * @param {Number} [height] Spriteの高さ. 459 * @param {Boolean} [staticOrDynamic] 静止するか動くか. 460 * @param {Number} [density] Spriteの密度. 461 * @param {Number} [friction] Spriteの摩擦. 462 * @param {Number} [restitution] Spriteの反発. 463 * @param {Boolean} [isSleeping] Spriteが初めから物理演算を行うか. 464 * @constructs 465 * @extends enchant.box2d.PhySprite 466 */ 467 initialize: function(width, height, staticOrDynamic, density, friction, restitution, isSleeping) { 468 enchant.box2d.PhySprite.call(this, width, height); 469 470 //物理オブジェクトの生成 471 this.body = this.createPhyBox(staticOrDynamic, density, friction, restitution, isSleeping); 472 } 473 }); 474 475 476 /** 477 * @scope enchant.PhyCircleSprite.prototype 478 */ 479 enchant.box2d.PhyCircleSprite = enchant.Class.create(enchant.box2d.PhySprite, { 480 /** 481 * 円の物理シミュレーション用Sprite 482 * @example 483 * var bear = new PhyCircleSprite(16, enchant.box2d.DYNAMIC_SPRITE, 1.0, 0.5, 0.3, true); 484 * bear.image = core.assets['chara1.gif']; 485 * 486 @param {Number} [radius] Spriteの半径. 487 * @param {Boolean} [staticOrDynamic] 静止するか動くか. 488 * @param {Number} [density] Spriteの密度. 489 * @param {Number} [friction] Spriteの摩擦. 490 * @param {Number} [restitution] Spriteの反発. 491 * @param {Boolean} [isSleeping] Spriteが初めから物理演算を行うか. 492 * @constructs 493 * @extends enchant.box2d.PhySprite 494 */ 495 initialize: function(radius, staticOrDynamic, density, friction, restitution, isSleeping) { 496 enchant.box2d.PhySprite.call(this, radius * 2, radius * 2); 497 498 //物理オブジェクトの生成 499 this.body = this.createPhyCircle(staticOrDynamic, density, friction, restitution, isSleeping); 500 } 501 }); 502 503 })(); 504