In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Box2Dの練習002 壁を追加してみた

FULL SCREENボタンに対応してみた
* 床オブジェクトが画面サイズに合わせて伸縮・位置変わります
* リサイズハンドラで処理をしています。
* 「CreateShape」で床オブジェクトのサイズを変更していますが、これで良いかは疑問・・・
* Createだと新たにオブジェクトを作っている・・・わけではないのでしょうか??
* 壁も追加してみた
/**
 * Copyright fumix ( http://wonderfl.net/user/fumix )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xfX4
 */

// forked from fumix's Box2Dの練習001 マウスでつかむ(FULL SCREENボタンに対応)
/**
* FULL SCREENボタンに対応してみた
* 床オブジェクトが画面サイズに合わせて伸縮・位置変わります
* リサイズハンドラで処理をしています。
* 「CreateShape」で床オブジェクトのサイズを変更していますが、これで良いかは疑問・・・
* Createだと新たにオブジェクトを作っている・・・わけではないのでしょうか??
* 壁も追加してみた
**/
package {
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import Box2D.Collision.Shapes.b2CircleDef;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;

	import flash.events.MouseEvent;

	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2World;
	import Box2D.Collision.b2AABB;

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

	/**
	 * @author fumix
	 */
        [SWF(width=465, height=465, backgroundColor=0x999999)]
	public class main extends MovieClip {

		private var _iterations : int;
		private var _timeStep : Number;
		private var _physScale : Number;

		private var _world : b2World;

		//マウスジョイント
		var _mouseJoint : b2MouseJoint;
		

		/**
		 * コンストラクタ
		 */
		public function main() : void {
			if (stage) onInit();
		 	else addEventListener(Event.ADDED_TO_STAGE, onInit);
		}

		/**
		 * 初期処理
		 */
		private function onInit(event : Event = null) : void {
			removeEventListener(Event.ADDED_TO_STAGE, onInit);
			
			//ステージ設定
			stage.align = "TL";
			stage.scaleMode = "noScale";
			
			_iterations = 10;		//制度
			_timeStep = 1.0 / 24.0;	//実行速度
			_physScale = 30;		//表示倍率
			
			//ワールドの定義
			var worldAABB : b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-100.0, -100.0);
			worldAABB.upperBound.Set(100.0, 100.0);
			//重力の定義
			var gravity : b2Vec2 = new b2Vec2(0.0, 10.0);
			//スリープのONOFF
			var doSleep : Boolean = true;
			//ワールドのインスタンス作成
			_world = new b2World(worldAABB, gravity, doSleep);
			//----------------------------------
			// 壁・床を作る
			//----------------------------------
			// 物体の定義を作る
			var wallBdDef : b2BodyDef = new b2BodyDef();
			var w : int = stage.stageWidth;
			var h : int = stage.stageHeight;
			wallBdDef.position.Set(0, h / _physScale);
			wallBdDef.angle = 0; //Math.PI / 24;

			// 形の定義を作る
			var wallShapeDef : b2PolygonDef = new b2PolygonDef();
			wallShapeDef.SetAsBox(w / _physScale, 10 / _physScale);
			wallShapeDef.friction = 1;		//摩擦力
			wallShapeDef.density = 0;		//密度
			wallShapeDef.restitution = 0.3;	//反発力

			// 床を作る
			var wallBd : b2Body = _world.CreateBody(wallBdDef);
			wallBd.m_userData = new Object();
			wallBd.m_userData.id = 'floor';
			// 床を追加する
			wallBd.CreateShape(wallShapeDef);

			// 壁を作る
			wallBdDef.position.Set(0, h / 2 / _physScale);
			wallShapeDef.SetAsBox(10 / _physScale, h / _physScale);

			wallBd = _world.CreateBody(wallBdDef);
			wallBd.m_userData = new Object();
			wallBd.m_userData.id = 'wall1';
			// 壁を追加する
			wallBd.CreateShape(wallShapeDef);

			// 壁を作る
			wallBdDef.position.Set(w / _physScale, h / 2 / _physScale);

			wallBd = _world.CreateBody(wallBdDef);
			wallBd.m_userData = new Object();
			wallBd.m_userData.id = 'wall2';
			// 壁を追加する
			wallBd.CreateShape(wallShapeDef);

			
			//----------------------------------
			// 物体を10表示
			//----------------------------------
			for(var i : int = 0;i < 10;i++) {
				var dx : Number = (stage.stageWidth / 10 * i);
				createObject(dx);
			}

			//----------------------------------
			// DebugDraw を有効にする
			//----------------------------------
			var debugDraw : b2DebugDraw = new b2DebugDraw();
			debugDraw.m_sprite = this;
			debugDraw.m_drawScale = _physScale;
			debugDraw.m_fillAlpha = 0.8;
			debugDraw.m_lineThickness = 1;
			debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
			_world.SetDebugDraw(debugDraw);
			
			//毎フレームの処理
			stage.addEventListener(Event.ENTER_FRAME, EnterFrame);
			//タイマーイベント(5秒毎に物体を降らせる)
			var timerObj:Timer = new Timer(5000);
			timerObj.addEventListener(TimerEvent.TIMER, onTimerHandler);
			timerObj.start();
			//イベントハンドラ
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);			
			//リサイズ処理
			stage.addEventListener(Event.RESIZE, resizeHandler);	

		}
		
		//リサイズ処理
		private function resizeHandler(event : Event) : void {
			//床の大きさ・位置を変更
			for (var b2body : b2Body = _world.m_bodyList;b2body; b2body = b2body.m_next) {
				if (b2body.m_userData) {
					var wallShapeDef : b2PolygonDef = new b2PolygonDef();
					if (b2body.m_userData.id == "floor") {
						wallShapeDef.SetAsBox(stage.stageWidth / _physScale, 10 / _physScale);
						b2body.CreateShape(wallShapeDef);
						b2body.SetXForm(new b2Vec2(b2body.GetPosition().x, stage.stageHeight / _physScale), 0);
					}
					if (b2body.m_userData.id == "wall1") {
						wallShapeDef.SetAsBox(10 / _physScale, stage.stageHeight / _physScale);
						b2body.CreateShape(wallShapeDef);
					}
					if (b2body.m_userData.id == "wall2") {
						wallShapeDef.SetAsBox(10 / _physScale, stage.stageHeight / _physScale);
						b2body.CreateShape(wallShapeDef);
						b2body.SetXForm(new b2Vec2(stage.stageWidth / _physScale, 0), 0);
					}
				}
			}
		}
		private function onTimerHandler(event : TimerEvent) : void {
				var dx : Number = stage.stageWidth*Math.random();
				createObject(dx);
		}
		private function mouseMoveHandler(event : MouseEvent) : void {
			// mouseJointがnullでないときだけ処理を実行する
			if (_mouseJoint) {
				var p2 : b2Vec2 = new b2Vec2(event.stageX / _physScale, event.stageY / _physScale);
				_mouseJoint.SetTarget(p2);           	
			}
		}

		private function mouseDownHandler(event : MouseEvent) : void {
			// マウスボタンを押したとき、該当のオブジェクト上にマウスカーソルがあるかを判定
			var body : b2Body = GetBodyAtMouse(event.stageX, event.stageY);
			//mouseJoint = b2MouseJoint(world.CreateJoint(mouseJointDef));
			if (body) {
				var md : b2MouseJointDef = new b2MouseJointDef();
				md.body1 = _world.m_groundBody;
				md.body2 = body;
				md.target.Set(event.stageX / _physScale, event.stageY / _physScale);
				md.maxForce = 500.0 * body.m_mass;
				md.timeStep = _timeStep;
				_mouseJoint = _world.CreateJoint(md) as b2MouseJoint;
				body.WakeUp();
			}
		}

		private function mouseUpHandler(event : MouseEvent) : void {
			// マウスボタンが離されたら,マウスボタンを切り離す
			if(_mouseJoint){
				_world.DestroyJoint(_mouseJoint);
				_mouseJoint = null;			
			}
		}

		//該当オブジェクトがあるかの判定
		private function GetBodyAtMouse(stageX : Number, stageY : Number) : b2Body {
			// Make a small box.
			var mousePVec : b2Vec2 = new b2Vec2();
			var mouseXWorldPhys : Number = stageX / _physScale;
			var mouseYWorldPhys : Number = stageY / _physScale;

			mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys);
			var aabb : b2AABB = new b2AABB();
			aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
			aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
	
			// Query the world for overlapping shapes.
			var k_maxCount : int = 10;
			var shapes : Array = new Array();
			var count : int = _world.Query(aabb, shapes, k_maxCount);
			var body : b2Body = null;
			for (var i : int = 0;i < count; ++i) {
				if (shapes[i].m_body.IsStatic() == false) {
					var tShape : b2Shape = shapes[i] as b2Shape;
					var inside : Boolean = tShape.TestPoint(tShape.m_body.GetXForm(), mousePVec);
					if (inside) {
						body = tShape.m_body;
						break;
					}
				}
			}
			return body;
		}

		
		private function EnterFrame(event : Event) : void {
	
			_world.Step(_timeStep, _iterations);

			//画面外に行ったオブジェクトを削除する
			var marginX : Number = 100;
			var marginY : Number = 100;
			for (var b : b2Body = _world.GetBodyList();b; b = b.GetNext()) {
				var xPos : Number = b.GetWorldCenter().x * _physScale;
				var yPos : Number = b.GetWorldCenter().y * _physScale;
				if (!b.m_userData && (xPos > stage.stageWidth + marginX || xPos < -marginX || yPos > stage.stageHeight + marginY)) {
					//マウスジョイントがある場合
					if(_mouseJoint) {
						if(_mouseJoint.m_body2 == b) {
							_world.DestroyJoint(_mouseJoint);
							_mouseJoint = null;			
						}
					}
					_world.DestroyBody(b);
				}
			}		
		}


		// 物体を1個作る
		private function createObject(mx : Number = 0,my : Number = 0) : void {
			// 物体の定義を作る
			var objBdDef : b2BodyDef = new b2BodyDef();
			objBdDef.position.Set(mx / _physScale, my / _physScale);
			objBdDef.angle = Math.PI / 2 * Math.random();

			// 形の定義を作る
			var shapeDef : b2PolygonDef = new b2PolygonDef();
			shapeDef.SetAsBox(30 / _physScale, 30 / _physScale);
			shapeDef.density = 1;
			shapeDef.restitution = 0.2;
			shapeDef.friction = 0.1;
			
			//サークルを作る
			var circleDef:b2CircleDef = new b2CircleDef();
			circleDef.radius = (20*Math.random()+10) / _physScale;
			circleDef.density = 1;
			circleDef.restitution = 0.4;
			circleDef.friction = 1;		

			// 物体を作る
			var objBd : b2Body = _world.CreateBody(objBdDef);

			// 形を物体に追加する
			//objBd.CreateShape(shapeDef);
			objBd.CreateShape(circleDef);

			// 重さ・重心を計算する
			objBd.SetMassFromShapes();
		}
		private function addCircle( ax:Number, ay:Number ):void
		{
			//任意の位置にCircleオブジェクト追加してく
			//手順 ShapeなDef→BodyなDef→worldで実体をつくる感じ
			var s:b2CircleDef = new b2CircleDef();
			s.density = 1;
			s.restitution = 0.2;
			s.radius = 0.2;
			
			var b:b2BodyDef = new b2BodyDef();
			b.position.Set( ax, ay );
			
			var bb:b2Body  = _world.CreateBody( b );
			var bs:b2Shape = bb.CreateShape( s );
			bb.SetMassFromShapes();
			
			//Shapeはあとでいじるので配列にいれとく
			bs.m_userData = Number(0);
			//circles.push( b2CircleShape(bs) );
		}
	}
}