關於flash as3的物理引擎真是不少,比較之後發現,在開源引擎當中Box2D算是比較不錯的了,http://www.box2dflash.org/docs/2.0.2/manual#Prerequisites全文詳細,現在從HelloWorld程式進行講解,把個人心得分享給大家!
這個引擎是先從建立一個世界對象開始的,他負責管理內部一切對象的記憶體和類比過程。要建立一個世界中的對象,首先我們需要為世界定義邊界地區,Box2D針對地區內的所有對象進行類比碰撞,地區的大小並不重要,但更適合的地區將提高程式效能,一般來講這個地區設定的要比示範地區更大一些,因為一旦對象在運動時到達了邊界,它就會被“凍結”並停止一切類比活動。
- var worldAABB:b2AABB = new b2AABB();
- worldAABB.lowerBound.Set(-100,-100);//左邊界、上邊界
- worldAABB.upperBound.Set(100,100);//右邊界、下邊界
下面我們要為這個世界設定重力了,就是下面這段代碼,其實這裡面的重力是用向量b2Vec2(x,y);來表示的,x代表水平運動,正數向右,負數向左,y代表垂直運動,正數向下,負數向上。同時我們需要再定義一個布爾型參數(我命名為doSleep),來表示是否允許睡眠,睡眠所代表的含義網上也沒有一個明確的介紹,這裡我簡要講解一下。因為你在這個世界中產生的一切對象,他們的類比效果都是Realtime Compute出來的,當doSleep=false的時候,即使物體停止了運動,電腦還是在不停的進行著運算,其實這是完全不必要的,所以一般都設為true,這樣當物體停止之後就不會進行無謂的cpu消耗了。
- var gravity:b2Vec2 = new b2Vec2(0,10);
- var doSleep:Boolean = true;
以上參數都準備好了,我們可以將它們傳入b2World對象中並將其執行個體化,這樣一個物理引擎的類比地區就做好了。
- var world:b2World = new b2World(worldAABB,gravity,doSleep);
讓我們開始在其中加入你想要類比的對象吧。本來在那個英文網站中給出的是5個步驟,但是我感覺還少點什麼,所以我又加了一條:
第一步、建立並定義剛體位置。這裡我做一下名詞解釋,在任何力的作用下,體積和形狀都不發生改變的物體叫做“剛體”;
- var ground:b2BodyDef = new b2BodyDef();
- ground.position.Set(10, 12);//這裡的位置也是用向量定義的
2、給剛體定義皮膚(注意這裡的皮膚並不具備物理引擎的屬性,因此才有了第四步);
- bodyDef.userData = _mc;//我們自己繪製的圖形
- addChild(bodyDef.userData);
3、用世界對象添加剛體執行個體,需要注意的是世界對象裡並沒有儲存body定義的引用;
- var body:b2Body = world.CreateBody(bodyDef);
4、根據皮膚形狀建立類比圖形類:摩擦力、密度、彈力等等;當密度為0的時候,物體是不會動的,相當於障礙物。摩擦力和彈力取值範圍是0~1,形狀的地區是由SetAsBox定義的,因為類比圖形和剛體都要求以中心點為註冊點,因此這裡的寬和高的值都是一半,同時需要注意,這裡數值單位並不是像素,而是米,1米=30像素,大家在傳值的時候可別忘記換算哦。
- var box:b2PolygonDef = new b2PolygonDef();//建立多邊形
- box.density = _density;
- box.friction = _friction;
- box.restitution = _restitution;
- box.SetAsBox(_halfWidth , _halfHeight);
5、在剛體上添加類比圖形執行個體;
- body.CreateShape(box);
6、根據剛體的密度和面積計算出品質,密度*面積=品質。
- body.SetMassFromShapes();
這裡有兩個重要的參數需要我們自己定義一下。一個是迭代次數,這裡我定義為m_iterations,建議迭代次數為10,這時一個比較合理的值,使用較少的迭代可以提高效能,但類比品質受到影響。同樣,使用更多的迭代效能有所下降,但提高了你的類比品質。另外一個參數是遊戲的重新整理頻率,我定義為m_timeStep,根據英文教程上記載,它採用的是1/60秒重新整理一次,但因為它的平台是c++,效能比AVM2虛擬機器高出數倍,完全可以這麼做,而在flash中我們一般設定成1/30就可以了。
- var m_iterations:Number = 10;
- var m_timeStep:Number = 1 / 30;
現在一切都準備好了,我們要讓所有對象類比運動。其實他也是通過偵聽幀頻率而不斷重新整理實現的,把上面那兩個參數傳入世界對象的Step方法中即可,同時我們需要遍曆世界中的一切對象,並對每個對象的座標和角度進行更新。
- addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
- function Update(e:Event):void
- {
- world.Step(m_timeStep, m_iterations);
- for (var bb:b2Body=world.m_bodyList; bb; bb=bb.m_next)
- {
- if (bb.m_userData is Sprite)
- {
- bb.m_userData.x=bb.GetPosition().x * 30;//這裡擷取的變數單位是米,乘以30轉換成像素單位
- bb.m_userData.y=bb.GetPosition().y * 30;
- bb.m_userData.rotation=bb.GetAngle() * (180 / Math.PI);
- }
- }
- }