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ペイン表示にするスクリプトのα版
文字サイズを拡大縮小するスクリプト
電卓を表示するブックマークレット
Twitterで費やした時間を表示するスクリプト
ニコニコのタグをプレビューするスクリプト
ニコニコで広告を消すスクリプト
同じカテゴリー(プログラミング)の記事
 GoogleReaderを3ペイン表示にするスクリプトのα版 (2009-07-26 22:00)
 クリック動作を無効にするジョークブックマークレット (2009-07-19 23:52)
 文字サイズを拡大縮小するスクリプト (2009-07-12 18:09)
 ダブルクリックでスクロールするスクリプト (2009-07-05 14:22)
 電卓を表示するブックマークレット (2009-06-27 21:40)
 ごくごく一部の顔文字を絵文字に置き換えるスクリプト (2009-05-21 23:06)
Posted by Handle at 22:01│Comments(0)プログラミング
コメントフォーム
上の画像に書かれている文字を入力して下さい
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。