cocos2d-x for wp 之Box2D的应用
本文大部分內容是基于fengyun1989的博文,自己只是加深鞏固而已
Box2d是一款用于2d游戲的物理引擎。在這個世界里創造出的物體都更接近于真實世界的物體。
首先,在項目添加Box2D.XNA.DLL。
新建一個頁面BOX2DLayer并繼承于CCLayer
重寫init函數,并添加下面這個常量:
由于平時我們都是用像素來描述游戲世界的,而在box2d里是用“米”進行描述的。所以我們需要進行轉化單位。設置一個常量,然后在需要的位置上用像素除以它就可以轉化成相對應的“米”
public static double PTM_RATIO = 32.0;?
接下來就是開始創造世界了。
Vector2 gravity = new Vector2(30.0f, 0.0f);bool doSleep = true;world = new World(gravity, doSleep);首先我們需要模擬出一個重力gravity。這里用一個2維矢量模擬重力并設置了一個值doSleep,用以指明對象不參與碰撞時,是否可以“休眠”。一個休眠的對象將不會花費處理時間,直到它與其實對象發生碰撞的時候才會“醒”過來。
這里說明一下物理世界的重力向量gravity。兩個參數分別表示物理世界中的X軸和Y軸方向上的重力數值。“+” “-”表示重力的方向
X軸正值表示向右,Y軸正值表示向上
?
接下來,該是為這個世界添加一些物體的時候了。
我在Android關于box2d應用中看到關于world創建一個物體的步驟:
1.創建物體皮膚 PolygonDef
2.創建物體剛體BodyDef
3.通過皮膚和剛體創建一個物體 body (body=body.createBody(BodyDef )body.createShape(PolygonDef))
?在wp里略有不同。
BodyDef ballBodyDef = new BodyDef();ballBodyDef.type = BodyType.Dynamic;//動態類型ballBodyDef.position=new Vector2((float)(100/PTM_RATIO),(float)(300/PTM_RATIO));ballBodyDef.userData=ball;body=world.CreateBody(ballBodyDef);CircleShape circle=new CircleShape();circle._radius=(float)(26.0/PTM_RATIO);FixtureDef ballShapeDef=new FixtureDef();ballShapeDef.shape=circle;ballShapeDef.density=1.0f;//質量:0代表靜態的物體,1代表運動物體ballShapeDef.friction=0.0f;//摩擦ballShapeDef.restitution=1.0f;//恢復力body.CreateFixture(ballShapeDef);首先一個BodyDef
接下來一個CircleShape
最后一個FixtureDef
相比Android的定義過程,不過是將PolygonDef換成了一個Shape,并將這個Shape付給一個Fixture,最后由這個fixture完成body的創建。
現在詳細說明一下上面代碼的含義:
我們指定body的類型為dynamic body。默認值是static body,那意味著那個body不能被移動也不會參與仿真。很明顯,我們想讓籃球參與仿真。
?設置body的user data屬性為籃球精靈。你可以設置任何東西,但是,你設置成精靈會很方便,特別是當兩個body碰撞的時候,你可以通過這個參數把精靈對象取出來,然后做一些邏輯處理。
這里使用了一個不同的shape類型--circle shape。
在這里,我們需要為這個fixture指定一些參數
其中,說明一下這個restitution(恢復力)。我們都知道,在物理世界是能量守恒的。而這個恢復力就是能量守恒的體現之一。如果設置為1,則物體在世界里的碰撞是完全彈性碰撞。我們也把球的摩擦力設置為0.這樣可以防止球在碰撞的時候,由于摩擦損失能量,導致來回碰撞的過程中會有一點點偏差。?
?
接下來,我們必須為我們的世界設置一個圍墻,免得球跳出了“屏幕”
View Code BodyDef groundBodyDef = new BodyDef();groundBodyDef.position = new Vector2(0, 0);Body groundBody = world.CreateBody(groundBodyDef);PolygonShape groundBox = new PolygonShape();//凸多邊形FixtureDef boxShapeDef = new FixtureDef();boxShapeDef.shape = groundBox;groundBox.SetAsEdge(new Vector2(0, 0), new Vector2((float)(winSize.width / PTM_RATIO), 0));groundBody.CreateFixture(boxShapeDef);groundBox.SetAsEdge(new Vector2(0, 0), new Vector2(0, (float)(winSize.height / PTM_RATIO)));groundBody.CreateFixture(boxShapeDef);groundBox.SetAsEdge(new Vector2(0, (float)(winSize.height / PTM_RATIO)), new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)));groundBody.CreateFixture(boxShapeDef);groundBox.SetAsEdge(new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)),new Vector2((float)(winSize.width / PTM_RATIO), 0));groundBody.CreateFixture(boxShapeDef);
詳細解釋一下上面的代碼:
首先創建一個body定義結構體,并且指定它應該放在左下角。
然后,使用world對象來創建body對象。(注意,這里一定要使用world對象來創建,不能直接new,因為world對象會做一些內存管理操作。)
?接著,為屏幕的每一個邊界創建一個多邊形shape。這些“shape”僅僅是一些線段。注意,我們把像素轉換成了“meter”。通過除以之前定義的比率來實現的。
?再創建一個fixture定義,指定shape為polygon shape。
?再使用body對象來為每一個shape創建一個fixture對象。
注意:一個body對象可以包含許許多多的fixture對象。
在完成上面之后。我們只是定義了物理世界,還沒開始進行物理模擬。所以還要對world設置物理模擬:
world.Step(dt, 10, 10);此函數表示讓物理世界開始進行物理模擬,后兩個參數含義分別是“速度迭代次數”和“位置迭代次數”。設置他們的范圍在8-10之間。
這里的數字越小,精度越小,但是效率更高。數字越大,仿真越精確,但同時耗時更多。8一般是個折中數值。
?
這里要注意,因為物理世界模擬具有持續性,所以應該將設置放在線程中,不斷讓物理世界進行模擬。
在init()里添加一個this.schedule(tick)。這里的tick就是一個“線程”
在tick里除了添加物理模擬之外,我們要使我們的小球精靈匹配物理仿真。因此,我們遍歷world對象里面的所有body,然后看body的user data屬性是否為空,如果不為空,就可以強制轉換成精靈對象。接下來,就可以根據body的位置來更新精靈的位置了。
View Code for (Body b = world.GetBodyList(); b != null; b = b.GetNext()){if (b.GetUserData() != null){CCSprite ballData = (CCSprite)b.GetUserData();ballData.position = new CCPoint((float)(b.GetPosition().X * PTM_RATIO),(float)(b.GetPosition().Y * PTM_RATIO));ballData.rotation = -1 * MathHelper.ToDegrees(b.GetAngle());}}最后在AppDelegate.cs里面的applicationDidFinishLaunching修改場景入口就可以看到效果了。
附上所有代碼:
View Code 1 class BOX2DLayer:CCLayer 2 { 3 //定義了一個“像素/米”的比率。當你在cocos2d里面指定一個body在哪個位置時,你使用的單位要是米 4 public static double PTM_RATIO = 32.0; 5 6 World world; 7 Body body; 8 CCSprite ball; 9 10 public override bool init() 11 { 12 if (!base.init()) 13 return false; 14 //獲取窗口大小 15 CCSize winSize = CCDirector.sharedDirector().getWinSize(); 16 17 CCLabelTTF title = CCLabelTTF.labelWithString("Boxing", "Arial", 24); 18 title.position = new CCPoint(winSize.width / 2, winSize.height / 2 - 50); 19 this.addChild(title, 1); 20 21 ball = CCSprite.spriteWithFile("images/ball"); 22 ball.position = new CCPoint(0, 300); 23 this.addChild(ball); 24 25 26 Vector2 gravity = new Vector2(30.0f, 0.0f); 27 bool doSleep = true; 28 world = new World(gravity, doSleep); 29 30 BodyDef groundBodyDef = new BodyDef(); 31 groundBodyDef.position = new Vector2(0, 0); 32 Body groundBody = world.CreateBody(groundBodyDef); 33 PolygonShape groundBox = new PolygonShape();//凸多邊形 34 FixtureDef boxShapeDef = new FixtureDef(); 35 boxShapeDef.shape = groundBox; 36 groundBox.SetAsEdge(new Vector2(0, 0), new Vector2((float)(winSize.width / PTM_RATIO), 0)); 37 groundBody.CreateFixture(boxShapeDef); 38 groundBox.SetAsEdge(new Vector2(0, 0), new Vector2(0, (float)(winSize.height / PTM_RATIO))); 39 groundBody.CreateFixture(boxShapeDef); 40 groundBox.SetAsEdge(new Vector2(0, (float)(winSize.height / PTM_RATIO)), 41 new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO))); 42 groundBody.CreateFixture(boxShapeDef); 43 groundBox.SetAsEdge(new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)), 44 new Vector2((float)(winSize.width / PTM_RATIO), 0)); 45 groundBody.CreateFixture(boxShapeDef); 46 47 BodyDef ballBodyDef = new BodyDef(); 48 ballBodyDef.type = BodyType.Dynamic;//動態類型 49 ballBodyDef.position=new Vector2((float)(100/PTM_RATIO),(float)(300/PTM_RATIO)); 50 ballBodyDef.userData=ball; 51 52 body=world.CreateBody(ballBodyDef); 53 CircleShape circle=new CircleShape(); 54 circle._radius=(float)(26.0/PTM_RATIO); 55 56 FixtureDef ballShapeDef=new FixtureDef(); 57 ballShapeDef.shape=circle; 58 ballShapeDef.density=1.0f;//質量:0代表靜態的物體,1代表運動物體 59 ballShapeDef.friction=0.0f;//摩擦 60 ballShapeDef.restitution=1.0f;//恢復力 61 body.CreateFixture(ballShapeDef); 62 63 64 this.schedule(tick); 65 return true; 66 } 67 68 void tick(float dt) 69 { 70 world.Step(dt, 10, 10); 71 72 for (Body b = world.GetBodyList(); b != null; b = b.GetNext()) 73 { 74 if (b.GetUserData() != null) 75 { 76 CCSprite ballData = (CCSprite)b.GetUserData(); 77 ballData.position = new CCPoint((float)(b.GetPosition().X * PTM_RATIO), 78 (float)(b.GetPosition().Y * PTM_RATIO)); 79 ballData.rotation = -1 * MathHelper.ToDegrees(b.GetAngle()); 80 } 81 } 82 } 83 84 public static new CCLayer node() 85 { 86 BOX2DLayer layer = new BOX2DLayer(); 87 if (layer.init()) 88 { 89 return layer; 90 } 91 else 92 layer = null; 93 return layer; 94 } 95 96 }?
?
?
?
轉載于:https://www.cnblogs.com/dieaz5/archive/2013/03/23/2977723.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的cocos2d-x for wp 之Box2D的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用例写到抽筋
- 下一篇: python计算标准差为什么分母要-1_