顯示具有 教學 標籤的文章。 顯示所有文章
顯示具有 教學 標籤的文章。 顯示所有文章

2011年7月27日 星期三

Box2D flash tutorial III–add MovieClip

繼上一篇我們簡單的試範了如何在Box2D的world建立可動及固定的物件

並利用Box2d內建的Debug用的Shape在晝面上顯了結果

在實務上不會是只用那些簡單的形狀就要發佈實作品

這一篇我們來說明如何把設計的圖連結及Box2D的物件

前一篇我們為了簡化Box2D的基本結構未加上任何的使用者操作

這一篇我們加個Space按鈕,按一下我們就增加一個動態的物件(請先focus在flash上)

先來看一下成果(圖片未做去背處理)

程式如下:

  1: package
  2: {
  3: 	import Box2D.Collision.Shapes.b2CircleShape;
  4: 	import Box2D.Collision.Shapes.b2PolygonShape;
  5: 	import Box2D.Common.Math.b2Vec2;
  6: 	import Box2D.Dynamics.Contacts.b2CircleContact;
  7: 	import Box2D.Dynamics.Joints.*;
  8: 	import Box2D.Dynamics.Joints.b2LineJointDef;
  9: 	import Box2D.Dynamics.b2Body;
 10: 	import Box2D.Dynamics.b2BodyDef;
 11: 	import Box2D.Dynamics.b2DebugDraw;
 12: 	import Box2D.Dynamics.b2FixtureDef;
 13: 	import Box2D.Dynamics.b2World;
 14: 	
 15: 	import assets.BlueBirds;
 16: 	import assets.RedBird;
 17: 	
 18: 	import flash.display.MovieClip;
 19: 	import flash.display.Sprite;
 20: 	import flash.events.Event;
 21: 	import flash.events.KeyboardEvent;
 22: 	import flash.ui.Keyboard;
 23: 	
 24: 	public class Box2DMovieClip extends Sprite
 25: 	{
 26: 		private var _world:b2World;
 27: 		private var scale:uint = 1;
 28: 		
 29: 		public function Box2DMovieClip()
 30: 		{
 31: 			super();
 32: 			this.stage.addEventListener(KeyboardEvent.KEY_DOWN,function(event:KeyboardEvent):void{
 33: 				switch(event.keyCode){
 34: 					case Keyboard.SPACE:
 35: 						dynamicRect();
 36: 						break;
 37: 				}
 38: 			});
 39: 			this.addEventListener(Event.ENTER_FRAME,function():void{
 40: 				_world.Step(1/30,10,10);
 41: 				_world.ClearForces();
 42: 				//_world.DrawDebugData();
 43: 				
 44: 				updateDisplayList();
 45: 			});
 46: 			
 47: 			this._world = new b2World(new b2Vec2(0,30),true);
 48: 			
 49: 			//現在套上實際的Shape 故這裡就用不到了
 50: 			/*var dbgDraw:b2DebugDraw = new b2DebugDraw();
 51: 			dbgDraw=new b2DebugDraw();
 52: 			dbgDraw.SetSprite(this);
 53: 			//dbgDraw.SetDrawScale(30.0);
 54: 			dbgDraw.SetFillAlpha(0.5);
 55: 			dbgDraw.SetLineThickness(1.0);
 56: 			dbgDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
 57: 			
 58: 			_world.SetDebugDraw(dbgDraw);*/
 59: 			
 60: 			this.fixRect();
 61: 			this.dynamicRect();
 62: 		}
 63: 		
 64: 		private function fixRect():void
 65: 		{
 66: 			var bird:RedBird = new RedBird();
 67: 			this.addChild(bird);
 68: 			
 69: 			var bd:b2BodyDef=new b2BodyDef();
 70: 			bd.position.Set(150, 100);
 71: 			bd.userData = bird
 72: 			
 73: 			var rect:b2PolygonShape=new b2PolygonShape();
 74: 			rect.SetAsBox(1, 1);
 75: 			
 76: 			var body:b2Body=_world.CreateBody(bd);
 77: 			
 78: 			var fd:b2FixtureDef=new b2FixtureDef();
 79: 			fd.shape=rect;
 80: 			fd.friction=0.3;
 81: 			fd.density=0;
 82: 			
 83: 			body.CreateFixture(fd);
 84: 		}
 85: 		
 86: 		private function dynamicRect():void
 87: 		{
 88: 			var bird:BlueBirds = new BlueBirds();
 89: 			this.addChild(bird);
 90: 			
 91: 			var x:Number = Math.random() *1000;
 92: 			
 93: 			var bd:b2BodyDef=new b2BodyDef();
 94: 			bd.position.Set(x, 50);
 95: 			bd.type=b2Body.b2_dynamicBody;
 96: 			bd.userData =bird;
 97: 			
 98: 			var rect:b2PolygonShape=new b2PolygonShape();
 99: 			rect.SetAsBox(1, 1);
100: 			
101: 			var body:b2Body=_world.CreateBody(bd);
102: 			
103: 			var fd:b2FixtureDef=new b2FixtureDef();
104: 			fd.shape=rect;
105: 			fd.friction=0.3;
106: 			fd.density=0;
107: 			
108: 			body.CreateFixture(fd);
109: 		}
110: 		
111: 		private function updateDisplayList():void
112: 		{
113: 			for (var bb:b2Body=_world.GetBodyList(); bb; bb=bb.GetNext())
114: 			{
115: 				var viewComp:Sprite=bb.GetUserData() as Sprite;
116: 				if (viewComp)
117: 				{
118: 					viewComp.x=bb.GetPosition().x;
119: 					viewComp.y=bb.GetPosition().y;
120: 					viewComp.rotation=bb.GetAngle() * (180 / Math.PI);
121: 				}
122: 			}
123: 		}
124: 
125: 	}
126: }








這次我們因為要用到實際的設計,所以我先把DebugSprite先註解掉(當然不註解掉仍然可以跑,基於效能問題,建議還是若己經實際的設計,就不要再放上了)   line 42 及line50~58









先在fixeRect及dynamicRect的function中加上我們的在flash定義的Symbol(class)並需要先將其加到場景上,不需去設定座標,因為接下的function可以讓Box2D跟我們的設計物件做連動









接著我們在EnterFrame事件裡除了Box2D世界的滾動的呼叫外,最重的就是Box2D跟設計物件連動的function updateDisplayList









加上這個function後即可看到設計物件如何被Box2D帶著走了









P.S.其中line 15~16的類別是定義在flash裡面的,讀者可自行在flash定義自己喜歡的圖片

2011年7月15日 星期五

Box2D flash tutorial II–Add shape

接著我們來我的世界中加上二個物件(Shape)

一個是固定的(b2_staticBody),一個是被地心引力往下吸的(b2_dynamicBody)

首先先來看一下程式

  1: package
  2: {
  3:     import Box2D.Collision.Shapes.b2PolygonShape;
  4:     import Box2D.Common.Math.b2Vec2;
  5:     import Box2D.Dynamics.b2Body;
  6:     import Box2D.Dynamics.b2BodyDef;
  7:     import Box2D.Dynamics.b2DebugDraw;
  8:     import Box2D.Dynamics.b2FixtureDef;
  9:     import Box2D.Dynamics.b2World;
 10: 
 11:     import flash.display.Sprite;
 12:     import flash.events.Event;
 13: 
 14:     public class Initialization extends Sprite
 15:     {
 16:         private var _world:b2World;
 17:         private var scale:uint=30;
 18: 
 19:         public function Initialization()
 20:         {
 21:             super();
 22:             this.addEventListener(Event.ENTER_FRAME, function():void
 23:             {
 24:                 _world.Step(1 / 30, 10, 10);
 25:                 _world.ClearForces();
 26:                 _world.DrawDebugData();
 27:             });
 28: 
 29:             this._world=new b2World(new b2Vec2(0, 1), true);
 30: 
 31: 
 32:             var dbgDraw:b2DebugDraw=new b2DebugDraw();
 33: 
 34:             dbgDraw=new b2DebugDraw();
 35:             dbgDraw.SetSprite(this);
 36:             dbgDraw.SetDrawScale(30.0);
 37:             dbgDraw.SetFillAlpha(0.5);
 38:             dbgDraw.SetLineThickness(1.0);
 39:             dbgDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
 40: 
 41:             _world.SetDebugDraw(dbgDraw);
 42: 
 43:             this.fixRect(); //add fix shape
 44:             this.dinamicRect(); //add dynamic shape
 45:         }
 46: 
 47:         private function fixRect():void
 48:         {
 49:             var bd:b2BodyDef=new b2BodyDef();
 50:             bd.position.Set(10, 10);
 51: 
 52:             var rect:b2PolygonShape=new b2PolygonShape();
 53:             rect.SetAsBox(2, 2);
 54: 
 55:             var body:b2Body=_world.CreateBody(bd);
 56: 
 57:             var fd:b2FixtureDef=new b2FixtureDef();
 58:             fd.shape=rect;
 59:             fd.friction=0.3;
 60:             fd.density=0;
 61: 
 62:             body.CreateFixture(fd);
 63:         }
 64: 
 65:         private function dinamicRect():void
 66:         {
 67:             var bd:b2BodyDef=new b2BodyDef();
 68:             bd.position.Set(5, 5);
 69:             bd.type=b2Body.b2_dynamicBody;
 70: 
 71:             var rect:b2PolygonShape=new b2PolygonShape();
 72:             rect.SetAsBox(2, 2);
 73: 
 74:             var body:b2Body=_world.CreateBody(bd);
 75: 
 76:             var fd:b2FixtureDef=new b2FixtureDef();
 77:             fd.shape=rect;
 78:             fd.friction=0.3;
 79:             fd.density=0;
 80: 
 81:             body.CreateFixture(fd);
 82:         }
 83:     }
 84: }
 85: 


 



在line29我們先把地方引力調小,這樣在往下掉的時侯會掉的慢點



line43加上一個固定的方塊



line44加上一個會隨地心引力的方塊



接著來說明如何把一個物件(shape)加到世界上



要加到世界上主要是有四個動作




  1. b2bodyDef指定其相關資料或屬性 default type:b2_staticBody


  2. 建立 b2XXXShape ,並設定共屬性


  3. 由世界建立一個身體(b2Body)


  4. 設定 b2FixtureDef 的各摩擦等各屬性


  5. 由建立出的身體把固定物(b2FixtureDef )做建立



做完以上的動作即完成物件加到世界上



下一篇我們來把一些自定的flash物件加到整個世界上

Box2D flash tutorial I - Initialization

使用BOX2D由於網上看到很多範例

若沒有促一說明,確實有點點感到複雜

這些說明應該適用於各種不同的版本

那初始主要分為二個部份

  1. 建立世界(b2world),設定其地心引力方向,並設doSleep為true
  2. 重覆執行一步一步(step),並清除力量(force)
  3. 加入測試繪圖資料(b2DebugDraw)

其實初始大概這麼做就夠了,大部份範例主要是使用其內建的繪圖,才會需要第三步驟,實際作業只需要前二步

不過若是只做了前二步,在畫面上是不會有任何,東西在動的,我們先來看一下程式

 

  1: package
  2: {
  3:     import Box2D.Common.Math.b2Vec2;
  4:     import Box2D.Dynamics.b2World;
  5:     import Box2D.Dynamics.b2DebugDraw;
  6: 
  7:     import flash.display.Sprite;
  8:     import flash.events.Event;
  9: 
 10:     public class Initialization extends Sprite
 11:     {
 12:         private var _world:b2World;
 13:         private var scale:uint=30;
 14: 
 15:         public function Initialization()
 16:         {
 17:             super();
 18:             this.addEventListener(Event.ENTER_FRAME, function():void
 19:             {
 20:                 _world.Step(1 / 30, 10, 10);
 21:                 _world.ClearForces();
 22:                 _world.DrawDebugData();
 23:             });
 24: 
 25:             this._world=new b2World(new b2Vec2(0, -30), true);
 26: 
 27: 
 28:             var dbgDraw:b2DebugDraw=new b2DebugDraw();
 29: 
 30:             dbgDraw=new b2DebugDraw();
 31:             dbgDraw.SetSprite(this);
 32:             dbgDraw.SetDrawScale(30.0);
 33:             dbgDraw.SetFillAlpha(0.5);
 34:             dbgDraw.SetLineThickness(1.0);
 35:             dbgDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
 36: 
 37:             _world.SetDebugDraw(dbgDraw);
 38:         }
 39:     }
 40: }
 41: 

 



以上程式算是對物理引擎設置好了基本環境,目前還未加上在世界裡的物件,所以執行時,不會看到任何東西,



物理引擎做的事是在協助我們在畫面上的物作可以做些實際的物理運動,所以當我們做運作時,是會由一些非可視物件關連到



我們的可視物件去做運動的,當我們還沒關連到畫面上的可視物件時,我們就可以先利用DebugDraw(line 28~37)來測試我們希望物理引擎幫我達到的效果(目前試了二個物理引擎,基本都是這樣設計的)



其中28~37為輔助在還未放上所以設計的圖片或DisplayObject時所用的內建繪圖,在整體完成作單時建議是要拿掉的



下個部份我們再來加上一些可運動物件或加一些固定的運件吧



 



2011/07/26 updated



接下來的後續篇及以上所使用的Lib是使用 Box2D 2.0 版的



為了有網友提到可能使用不相同的版本,造成某些資料不同,故提供flex所建的 liberary project及swc給有需的人下載




  1. Library Project:file link


  2. Swc file:file link