« Box2D FLASH その3 地面の作成 | トップページ | Box2D FLASH その5 マウスでドラッグ »

2008年4月25日 (金)

Box2D FLASH その4 MovieClipの表示

これまでのサンプルではBOXをgraphicsで描画しましたが
今度はライブラリにあるMovieClipを表示するようにしてみます。

まずMovieClipを1つ作り、リンケージでクラス名を「BoxFace」にしておいてください。
MovieClipの中にはとりあえずはシェイプでも画像でもいいので四角いものをおいてください。
四角の中心点がMovieClipの原点になるようにしておきます。
(MovieClipはアニメーションしてても大丈夫です)

●BOXの作成

ではBOXを作成します。
これまでのとほぼ同じですが、以下の赤い部分が違ってます。

//BOXの作成
var boxDef:b2BoxDef = new b2BoxDef();
boxDef.extents.Set(40, 20);
boxDef.density = 0.2;
boxDef.friction = 0.8;
boxDef.restitution = 0.6;
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.AddShape(boxDef);
bodyDef.position.x = 200;
bodyDef.position.y = 200;
bodyDef.userData = new BoxFace();	//BoxFaceはリンケージしてあるもの
bodyDef.userData.width = boxDef.extents.x * 2;
bodyDef.userData.height = boxDef.extents.y * 2;
var body:b2Body = m_world.CreateBody(bodyDef);
addChild(bodyDef.userData);

今度は「userData」に先ほどのMovieClipのインスタンスの参照を入れています。
ここで勘違いしてはいけないのが、
「こうすればMovieClipを表示できるようになる」というわけではなく、
「こうしなければいけない」というわけでもありません。
「userData」には描画に関するものを入れておくと便利っぽいというだけです。
対応するMovieClipのインスタンスの参照が楽なだけです。

> bodyDef.userData.width = boxDef.extents.x * 2;
> bodyDef.userData.height = boxDef.extents.y * 2;

「bodyDef.userData」は「BoxFace」のインスタンスの参照になっています。
なので「bodyDef.userData.width」は「BoxFace」のインスタンスのwidthプロパティです。
通常は「BoxFace」のインスタンスのサイズをBOXの領域にぴったり合わせます。
boxDef.extents.Set(40, 20);
で設定しているのがBOXの半径です。
この中の「40」の部分は「boxDef.extents.x」で、
「20」の部分は「boxDef.extents.y」で取得できます。
実際のBOXのサイズはこの倍なので2倍したサイズにします。

> addChild(bodyDef.userData);
最後に「BoxFace」のインスタンスをaddChildして表示させます。
bodyDef.userDataは「BoxFace」のインスタンスの参照になっているのでこう書けます。

●描画
描画をします。

これまでのはシェイプで表示するオブジェクトしかありませんでしたが、
今回はBOXはMovieClipで、地面はシェイプで表示させるので2種類のパターン
があります。
そのため場合分けをする必要があります。

場合分けのやり方は単に「userData」の中身が「Sprite(or MovieClip)かどうか」でやります。
(他にもいろいろやり方はあります。作る内容によって変わるかと)

for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
	if (bb.m_userData is Sprite) {
		//bb.m_userDataがSprite、またはMovieClipの時
		bb.m_userData.x = bb.m_position.x;
		bb.m_userData.y = bb.m_position.y;
		bb.m_userData.rotation = bb.m_rotation * (180/Math.PI);
	} else {
		//上記以外の時。この場合はシェイプ
		for (var s:b2Shape = bb.GetShapeList(); s != null; s = s.GetNext()) {
			drawShape(s, bb.m_userData.fillColor);
		}
	}
}

> for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
オブジェクトを1つずつ見ていきます。

> if (bb.m_userData is Sprite) {
実際はMovieClipだけどSpriteでやっても大丈夫みたいです。
「userData」ではなく「m_userData」になってるのは
ここの「bb」が「b2BodyDef」ではなく「b2Body」だからです。(ややこしい。。)
m_world.CreateBody(bodyDef);
とした時に「b2BodyDef」から「b2Body」が生成されます。
この時に「b2BodyDef.userData」の内容が「b2Body.m_userData」にコピーされます。
このループではBox2Dのステージにある「b2Body」のリストを1つずつ見てます。

> //bb.m_userDataがSprite、またはMovieClipの時
> bb.m_userData.x = bb.m_position.x;
> bb.m_userData.y = bb.m_position.y;
> bb.m_userData.rotation = bb.m_rotation * (180/Math.PI);

「bb.m_userData」というのはこの場合ではさっきの「BoxFace」のインスタンスの参照になります。
「bb.m_position」「bb.m_rotation」は計算結果が入ってるので、その値の場所へ
「BoxFace」のインスタンスを移動させ、さらにrotationも変化させます。
これだけで動作します。
(userDataにインスタンスの参照が入ってるとここが楽になります)

> //上記以外の時。この場合はシェイプ
> for (var s:b2Shape = bb.GetShapeList(); s != null; s = s.GetNext()) {
>  drawShape(s, bb.m_userData.fillColor);
> }
ここはこれまでのと同じです。

package {
	import flash.display.Sprite;
	import flash.events.Event;

	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Dynamics.Joints.*;
	import Box2D.Common.Math.*;
	public class Box2D0430Test03 extends Sprite {
		public var m_world:b2World;
		public var m_iterations:int = 1;
		public var m_timeStep:Number = 1/60;
		public var m_sprite:Sprite;
		public var m_physScale:Number = 1;
		function Box2D0430Test03() {
			init();
		}
		public function init():void {
			//Box2D 計算&描画用のENTER_FRAMEの設定
			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
			
			//シェイプ描画用のSpriteを作成
			m_sprite = new Sprite();
			addChild(m_sprite);
			
			//Box2Dのステージを作成
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.minVertex.Set(-1000.0, -1000.0);
			worldAABB.maxVertex.Set(1000.0, 1000.0);
			var gravity:b2Vec2 = new b2Vec2(0.0, 100.0);	//重力(X方向、Y方向)
			var doSleep:Boolean = false;	//これまだ不明。。
			m_world = new b2World(worldAABB, gravity, doSleep);

			//BOXの作成
			var boxDef:b2BoxDef = new b2BoxDef();
			boxDef.extents.Set(40, 20);
			boxDef.density = 0.2;
			boxDef.friction = 0.8;
			boxDef.restitution = 0.6;
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.AddShape(boxDef);
			bodyDef.position.x = 200;
			bodyDef.position.y = 200;
			bodyDef.userData = new BoxFace();	//BoxFaceはリンケージしてあるもの
			bodyDef.userData.width = boxDef.extents.x * 2;
			bodyDef.userData.height = boxDef.extents.y * 2;
			var body:b2Body = m_world.CreateBody(bodyDef);
			addChild(bodyDef.userData);
			
			//地面の作成
			//var boxDef:b2BoxDef = new b2BoxDef();
			boxDef.extents.Set(400, 20);
			boxDef.density = 0.0; //ここを0にすると動かない!
			boxDef.friction = 0.8;
			boxDef.restitution = 0.6;
			//var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.AddShape(boxDef);
			bodyDef.position.x = 400;
			bodyDef.position.y = 500;
			bodyDef.userData = { };
			bodyDef.userData.fillColor = 0x000000;
			m_world.CreateBody(bodyDef);
		}

		public function Update(e:Event):void {
			//Box2Dに計算をさせる
			m_world.Step(m_timeStep, m_iterations);
			
			//シェイプを全て削除
			this.m_sprite.graphics.clear();
			
			for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
				if (bb.m_userData is Sprite) {
					//bb.m_userDataがSprite、またはMovieClipの時
					bb.m_userData.x = bb.m_position.x;
					bb.m_userData.y = bb.m_position.y;
					bb.m_userData.rotation = bb.m_rotation * (180/Math.PI);
				} else {
					//上記以外の時。この場合はシェイプ
					for (var s:b2Shape = bb.GetShapeList(); s != null; s = s.GetNext()) {
						drawShape(s, bb.m_userData.fillColor);   
					}   
				}
			}
		}
		
		public function drawShape(_shape:b2Shape, _fillColor:int = 0xFFFFFF):void {
			//シェイプの描画 このへんはコピペで。。
			var i:int;
			var v:b2Vec2;
			var poly:b2PolyShape = _shape as b2PolyShape;   
			var tV:b2Vec2 = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));   
			m_sprite.graphics.beginFill(_fillColor, 1);
			m_sprite.graphics.lineStyle(0, 0, 0);
			m_sprite.graphics.moveTo(tV.x * m_physScale, tV.y * m_physScale);
			for (i = 0; i < poly.m_vertexCount; ++i){
				v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
				m_sprite.graphics.lineTo(v.x * m_physScale, v.y * m_physScale);
			}
			m_sprite.graphics.lineTo(tV.x * m_physScale, tV.y * m_physScale);
			m_sprite.graphics.endFill();
		}
	}
}

|

« Box2D FLASH その3 地面の作成 | トップページ | Box2D FLASH その5 マウスでドラッグ »

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: Box2D FLASH その4 MovieClipの表示:

« Box2D FLASH その3 地面の作成 | トップページ | Box2D FLASH その5 マウスでドラッグ »