2008年12月02日
Box2DFlashAS3にさわってみた
今回はBox2DFlashAS3を使ってみました。 いわゆる物理演算エンジンなんですが、 演算と表示が別々になっているので、この対応を取るのに苦労したの何のって・・・。
適当にクリックすると丸とか四角とかが降ってきます。 クリックしすぎると重くなるかもしれないのでほどほどに。
FlashPlayer9以上が必要です。
package { import Box2D.Collision.b2AABB; import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2World; import flash.display.MovieClip; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Box2DFlashAS3 extends Sprite { private var world:b2World; // 物理演算の設定 private const PHYS_SCALE:Number = 1; private const PHYS_ITERATION:uint = 10; private const PHYS_STEP:Number = 1 / 30; // その他定数 private const GRAVITY:b2Vec2 = new b2Vec2(0.0, 300.0); private const ST_WIDTH:Number = 300; private const ST_HEIGHT:Number = 225; /** * コンストラクタ */ public function Box2DFlashAS3() { var worldAABB:b2AABB = new b2AABB(); worldAABB.lowerBound.Set(-1000.0, -1000.0); // 演算を行う範囲 worldAABB.upperBound.Set(1000.0, 1000.0); this.world = new b2World(worldAABB, GRAVITY, true); // 壁 this.createWall(); // 物理演算開始 this.addEventListener(Event.ENTER_FRAME, update, false, 0, true); // クリックした位置からランダムな大きさのオブジェクトを落下させる stage.addEventListener(MouseEvent.CLICK, function (evt:MouseEvent) { if(Math.random() < 0.5) { createBall(evt.stageX, evt.stageY, Math.random() * 10 + 20); } else { createBlock(evt.stageX, evt.stageY, Math.random() * 10 + 20, Math.random() * 10 + 20); } }); } /** * 壁を作成 */ private function createWall():void { /* b2PolygonDef.SetAdBox(width, height) * 中心から上下にheight、左右にwidthだけの大きさのボックスを作る * +-------------+ * | height | * |width o width| * | height | * +-------------+ * 幅はwidthの2倍、高さはheightの二倍になる * MovieClipを表示に使う場合、基準点をMovieClipの中心にしないとずれる */ const FRICTION:Number = 0.3; const RESTITUTION:Number = 0.8; const TICK:Number = 5 / 2; const WALL_WIDTH:Number = ST_WIDTH / 2; const WALL_HEIGHT:Number = ST_HEIGHT /2 var shapeDef:b2PolygonDef = new b2PolygonDef();; shapeDef.friction = FRICTION; shapeDef.restitution = RESTITUTION; var bodyDef:b2BodyDef = new b2BodyDef();; shapeDef.density = 0; var body:b2Body; // 上 shapeDef.SetAsBox(WALL_WIDTH, TICK); bodyDef.position.Set(WALL_WIDTH, TICK); body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); // 下 shapeDef.SetAsBox(WALL_WIDTH, TICK); bodyDef.position.Set(WALL_WIDTH, ST_HEIGHT - TICK); body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); // 左 shapeDef.SetAsBox(TICK, WALL_HEIGHT); bodyDef.position.Set(TICK, WALL_HEIGHT); body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); // 右 shapeDef.SetAsBox(TICK, ST_HEIGHT); bodyDef.position.Set(ST_WIDTH - TICK, WALL_HEIGHT); body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); // 斜め shapeDef.SetAsBox(TICK, ST_WIDTH); bodyDef.position.Set(ST_WIDTH, WALL_HEIGHT); bodyDef.angle = Math.PI / 4; body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); } /** * ボールを生成 * @param px X座標 * @param py Y座標 * @param r 半径 * @return void */ private function createBall(px:Number = 0, py:Number = 0, r:Number = 30):void { // シェイプ 物理演算の対象 var shapeDef:b2CircleDef = new b2CircleDef(); shapeDef.radius = r; shapeDef.density = 1.0; shapeDef.friction = 0.3; shapeDef.restitution = 0.8; // ボディ 表示対象 var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set(px / PHYS_SCALE, py / PHYS_SCALE); bodyDef.userData = new MCball(); bodyDef.userData.x = px * PHYS_SCALE; bodyDef.userData.y = py * PHYS_SCALE; bodyDef.userData.width = r * 2; bodyDef.userData.height = r * 2; // ボディの実体化 var body:b2Body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); // # なにをやってるのか不明・・・ this.addChild(bodyDef.userData); } /** * 長方形を生成 * @param px * @param py * @param w * @param h */ private function createBlock(px:Number = 0, py:Number = 0, w:Number = 30, h:Number = 30):void { var shapeDef:b2PolygonDef = new b2PolygonDef(); shapeDef.SetAsBox(w / 2, h / 2); shapeDef.density = 1.0; shapeDef.friction = 0.3; shapeDef.restitution = 0.8; var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set(px / PHYS_SCALE, py / PHYS_SCALE); bodyDef.userData = new MCblock(); bodyDef.userData.x = px; bodyDef.userData.y = py; bodyDef.userData.width = w; bodyDef.userData.height = h; var body:b2Body = this.world.CreateBody(bodyDef); body.CreateShape(shapeDef); body.SetMassFromShapes(); this.addChild(bodyDef.userData); } /** * 更新 * @param evt */ private function update(evt:Event) { this.world.Step(PHYS_STEP, PHYS_ITERATION); for(var bb:b2Body = this.world.GetBodyList(); bb; bb = bb.GetNext()) { var bud = bb.GetUserData(); if(bud is Sprite) { bud.x = bb.GetPosition().x * PHYS_SCALE; bud.y = bb.GetPosition().y * PHYS_SCALE; bud.rotation = bb.GetAngle() * (180 / Math.PI); } } } } }
動く部品とかもあるみたいだけど気力切れ。 これだけやるのに時間かかりすぎです・・・。
リセットボタンも付けたかったけど ActionScriptでリセットする方法がわからなかったので未実装。 とりあえず宿題ということで。
GoogleReaderを3ペイン表示にするスクリプトのα版
クリック動作を無効にするジョークブックマークレット
文字サイズを拡大縮小するスクリプト
ダブルクリックでスクロールするスクリプト
電卓を表示するブックマークレット
ごくごく一部の顔文字を絵文字に置き換えるスクリプト
クリック動作を無効にするジョークブックマークレット
文字サイズを拡大縮小するスクリプト
ダブルクリックでスクロールするスクリプト
電卓を表示するブックマークレット
ごくごく一部の顔文字を絵文字に置き換えるスクリプト
Posted by Handle at 22:01│Comments(0)│プログラミング
コメントフォーム