Flashで物理演算を使ったミニゲーム その2「WorldとBodyとジョイント」【Flash・lemonovel】

flash_015
Flashで物理演算を使ったミニゲーム その1「Box2Dについて」
Flashで物理演算を使ったミニゲーム その2「WorldとBodyとジョイント」
Flashで物理演算を使ったミニゲーム その3「動かないBody」
Flashで物理演算を使ったミニゲーム その4「カウントダウンするタイマーと動くBody」
Flashで物理演算を使ったミニゲーム その5「動かないBodyに衝突した時の処理」
Flashで物理演算を使ったミニゲーム その6「動くBodyに衝突した時の処理」
Flashで物理演算を使ったミニゲーム その7「効果音・BGM・背景」
Flashで物理演算を使ったミニゲーム その8「lemonovelで使う」

前回Box2Dを使うという説明でしたが
実際に使ってみます。

実際のコードは一番下に書きます。
flaファイル・asファイルと同じ階層に「Box2D」のフォルダをコピーしたら
「import Box2D.Collision.b2AABB ……」という感じにインポートします。

「createWorld」で「World」という構成要素を作ります。
Worldでは重力や物理演算の範囲などをセットアップします。
下記のソースでは画面の上下左右に動きのない物体を配置して壁を作っています。
この作業をしなくてはならない訳ではもちろんないんですが
オブジェクトを作っても物理演算に従って動き、画面の外のどっかに行ってしまいます。

「createMy」で「Body」という構成要素を作ります。
「Body」はサークル型かキューブ型のコンテナで
摩擦・反発・密度などを設定できます。
「createWorld」と「createMy」はそれぞれコンストラクタから呼び出して使います。

下記のソースではサークル型で
密度は0.3
反発は0.2
摩擦は0.5のコンテナになっています。

circleDef.density = 0.3;
circleDef.friction = 0.2;
circleDef.restitution = 0.5;

また、後から衝突時にどのコンテナとぶつかったのか判定するため

bodyDef.userData.id = 'id_my';
bodyDef.userData.name = 'na_my';

で名前をつけています。

ジョイントのクラスは
コンテナ同士を繋いだり、歯車・直動・滑車のジョイントがありますが
下記ソースではマウスとコンテナを繋ぐジョイントを作っています。
画面をドラッグするとジョイントでコンテナを動かすことが出来ます。

コンテナやジョイントは描画しなくてもいいのですがわかりやすく描画しています。

[SWF]http://oblsk.sakura.ne.jp/help/wp-content/uploads/2016/01/game02.swf,800,600[/SWF]
画面をドラッグして動きを試せます。
ステージ側には
ステージが白いと見難いため、黒平面オブジェクトを50%にして敷いてます。
ライブラリには、自分として使われている画像がmyというクラス名でASリンゲージされています。
用意したpng画像をシンボルに変換後
flash_009
こんな感じに。

そのシンボルをそのまま使うと描画した物体のラインと画像がズレます。
flash_010

これは無理にas側で修正せずに
シンボルを編集して
「0,0」の座標が画像の左上に来ているのを
flash_011 flash_012
画像の中心が「0,0」の座標になるようにしてしまえばぴったり合います。
flash_013 flash_014

◆サンプルソース全文

package{

	//////////////////////////////////////////////////////////////////////////////
	// インポート			
	//////////////////////////////////////////////////////////////////////////////

	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import flash.events.Event;

	import Box2D.Common.Math.*;
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;

	import Box2D.Dynamics.Joints.b2Joint;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import Box2D.Dynamics.Joints.b2RevoluteJoint;
	import Box2D.Dynamics.Joints.b2RevoluteJointDef;

	import flash.events.MouseEvent;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.text.*;

public class game02 extends Sprite{

        //定数定義
        private static const DRAW_SCALE:Number = 30;

		// ジョイントの定義
		private var mouseJointDef:b2MouseJointDef;
		private var mouseJoint:b2MouseJoint;

		// 値セット用
		private var centerX:Number;
		private var centerY:Number;

		public function game02(){

			createWorld();
			createMy();

			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);

		}


		//////////////////////////////////////////////////////////////////////////////
		// ワールドの作成			
		//////////////////////////////////////////////////////////////////////////////
			
		private function createWorld():void{

     		//物理エンジンのセットアップ
     		var worldAABB:b2AABB = new b2AABB();
     		worldAABB.lowerBound.Set(-100,-100);
     		 worldAABB.upperBound.Set(100,100);
			
			//重力のセットアップ
			var gravity:b2Vec2 = new b2Vec2(0.0, 0.4);
			
			//範囲・重力・スリープの有無
			var doSleep:Boolean = true;
			
			// ワールド内のセットアップ
			m_world = new b2World(worldAABB, gravity, true);

			// ワールド内座標の設定
			centerX = stage.stageWidth / 2 / DRAW_SCALE;
			centerY = stage.stageHeight / 2 / DRAW_SCALE;

			// 上
			var bodyTop:b2BodyDef = new b2BodyDef();
			bodyTop.position.Set(centerX, 0);
			var topShapeDef:b2PolygonDef = new b2PolygonDef();
			topShapeDef.SetAsBox(centerX, 0.2);
			topShapeDef.density = 0;
			
			// 下
			var bodyBottom:b2BodyDef = new b2BodyDef();
			bodyBottom.position.Set(centerX, centerY * 2);
			var BottomShapeDef:b2PolygonDef = new b2PolygonDef();
			BottomShapeDef.SetAsBox(centerX, 0.2);
			BottomShapeDef.density = 0;
			
			// 右
			var bodyRight:b2BodyDef = new b2BodyDef();
			bodyRight.position.Set(centerX * 2, centerY);
			bodyRight.angle = Math.PI;
			var rightShapeDef:b2PolygonDef = new b2PolygonDef();
			rightShapeDef.SetAsBox(0.2, centerY);
			rightShapeDef.density = 0;
			
			// 左
			var bodyLeft:b2BodyDef = new b2BodyDef();
			bodyLeft.position.Set(0, centerY);
			bodyLeft.angle = Math.PI;
			var leftShapeDef:b2PolygonDef = new b2PolygonDef();
			leftShapeDef.SetAsBox(0.2, centerY);
			leftShapeDef.density = 0;
			
			var top:b2Body = m_world.CreateBody(bodyTop);
			top.CreateShape(topShapeDef);
			
			var bottom:b2Body = m_world.CreateBody(bodyBottom);
			bottom.CreateShape(BottomShapeDef);
			
			var right:b2Body = m_world.CreateBody(bodyRight);
			right.CreateShape(rightShapeDef);
			
			var left:b2Body = m_world.CreateBody(bodyLeft);
			left.CreateShape(leftShapeDef);


			// 描画設定
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			debugDraw.m_sprite = this;
			debugDraw.m_drawScale = DRAW_SCALE;
			debugDraw.m_fillAlpha = 0.3;
			debugDraw.m_lineThickness = 1;
			debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
			m_world.SetDebugDraw(debugDraw);
			
			// イベントハンドラの登録
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);			
			
		}

		//////////////////////////////////////////////////////////////////////////////
		// 自分の作成
		//////////////////////////////////////////////////////////////////////////////
				
		private function createMy():void{
			
			var body:b2Body;
			var bodyDef:b2BodyDef;
			var boxDef:b2PolygonDef;
			var circleDef:b2CircleDef;
			
			bodyDef = new b2BodyDef();
			bodyDef.position.x = 10;
			bodyDef.position.y = 15;
			
			circleDef = new b2CircleDef();
			circleDef.radius = 1.66;
			circleDef.density = 0.3;
			circleDef.friction = 0.2;
			circleDef.restitution = 0.5;
			bodyDef.userData = new my();
			bodyDef.userData.id = 'id_my';
			bodyDef.userData.name = 'na_my';
			bodyDef.userData.enable = true;
			bodyDef.userData.width = 100; 
			bodyDef.userData.height = 100; 
			
			body = m_world.CreateBody(bodyDef);
			body.CreateShape(circleDef);
			
			body.SetMassFromShapes();
			addChild(bodyDef.userData);
			
			// ジョイントの定義
			mouseJointDef = new b2MouseJointDef();
			mouseJointDef.body1 = m_world.GetGroundBody();
			mouseJointDef.body2 = body;
			mouseJointDef.target = body.GetWorldCenter();
			mouseJointDef.maxForce = 30;
			mouseJointDef.timeStep = 1 / 24;
			
		}			


		//////////////////////////////////////////////////////////////////////////////
		// ジョイントの処理			
		//////////////////////////////////////////////////////////////////////////////
		
		private function mouseDownHandler(event:MouseEvent):void {
			mouseJoint = b2MouseJoint(m_world.CreateJoint(mouseJointDef));
		}
		
		private function mouseUpHandler(event:MouseEvent):void {
			m_world.DestroyJoint(mouseJoint);
			mouseJoint = null;
		}
		
		private function mouseMoveHandler(event:MouseEvent):void {
			if (mouseJoint) {
				var x:Number = event.stageX / DRAW_SCALE;
				var y:Number = event.stageY / DRAW_SCALE;
				mouseJoint.SetTarget(new b2Vec2(x, y));
			}
		}

		public function Update(e:Event):void{
			
			m_world.Step(m_timeStep, m_iterations);

			for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next){
				if (bb.m_userData is Sprite){
					bb.m_userData.x = bb.GetPosition().x * 30;
					bb.m_userData.y = bb.GetPosition().y * 30;
					bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
					
					if (bb.m_userData.enable == false) {   

						m_world.DestroyBody(bb); 
						removeChild(getChildByName(bb.m_userData.name));
					
					} 
				}
			}

		}

		private function enterFrameHandler(event:Event):void {

			m_world.Step(1 / 24, 10);

		}
		
		public var m_world:b2World;
		public var m_iterations:int = 10;
		public var m_timeStep:Number = 1.0/30.0;

	}


}

◆スポンサードリンク – 楽天市場
 

コメント

タイトルとURLをコピーしました