APE 2D引擎教程

最近Actionscript3.0出來之後,我決定搞一個物理引擎。其實早在2006年低,我就專門花了一些時間系統地學習了經典力學和相關的數學知識, 但那時我對如何編寫一個遊戲的物理引擎沒有一點思路。

Alec Cove實現了這個想法。 他爲Flash CS3和Flex寫出了一個物理引擎,而且非常易於使用。通過這個引擎你可以創建非常cool的東西。在我們開始這個教程之前,先準備下載這個引擎的代碼. 可以直接使用subversion下載源碼和api文檔, 具體的方法是: svn checkout http://ape.googlecode.com/svn/trunk/ ape-read-only。

你還可以到http://groups.google.com/group/ape-general/topics上參與APE引擎的一些討論。

我將使用FlashDevelop來創建一個APE引擎的基本場景。(譯者: 原文作者使用Flex 2)
我們將創建一個CarDemo的as文件, 其中代碼如下:

package  {
     import Flash.display.*;

     public class CarDemo extends Sprite {

           public function CarDemo() {

           }
     }
}

在編寫as文檔類時,我喜歡做的第一件事就是設置場景的背景顏色和幀頻。

package {
     import Flash.display.*;

     [SWF(backgroundColor="#115A70", frameRate="60")]
     public class CarDemo extends Sprite {

          public function CarDemo()  {

          }
     }
}

下一步就是導入APE引擎包。並且設置一下舞臺的屬性。我們禁止了Flash player的自動縮放功能,並設置場景爲左上對齊。

APE引擎是一個靜態類,所以我們不需要實例化它。在下面的步驟裏,我們將初始化APE引擎,並設置它的模擬速度。如果設置的模擬速度太高,我相信它會產生精度上的損失。

下面我們將把一個容器傳遞給APEngine。一個容器是引擎的可視化部分。在以上的代碼裏,CarDemo繼承了Sprite類。然後我們把this傳遞給ape engine。如果我們的CarDemo繼承的是MovieClip,這樣做也是沒有問題的。(譯者: 因爲MovieClip本身也是繼承Sprite的)

然後我們創建一個力(massless force),並應用到加入引擎的所有不固定的物體上。這個力就是重力(gravity)。一個矢量(vector)簡單地表示一個物體對象,並通過x, y值來表示相對與舞臺的位置。 當我們增加一個力到一個矢量物體(0, 1)上,這即表示我們不希望這個矢量物體水平移動,而僅僅垂直運動1個像素。

package {
     import Flash.display.*;
     import org.cove.ape.*;

     [SWF(backgroundColor="#115A70", frameRate="60")]

     public class CarDemo extends Sprite {

          public function CarDemo() {
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT;
                APEngine.init(1/4);
                APEngine.container = this;
                APEngine.addMasslessForce(new Vector(0,1));
          }
     }
}

我們最後的工作是需要啓動引擎,即通過ENTER_FRAME事件調用run方法。關於這一點有很多爭論,你也可以使用基於timer來調用run方法。run方法的目的是通知APE開始計算下一幀,並渲染結果到容器上(還記得我們前面把this傳給了APE引擎了嗎?)。APE運行後,會盡可能地接近我們設置的幀頻(60fps)。
(譯者: 1. 這裏的run函數調用可以理解爲遊戲循環, 即Game Loop, 主要是flash已經內部封裝了windows消息機制。2. 這裏的ENTER_FRAME事件肯定是不準確的,它依賴與我們每一幀的處理速度。3. 這裏容器Container是as3的概念,容易混淆, as3中把它作爲一個顯示的平臺,我們可以理解爲一個frame, plane, 或者surface。當然container還實現了一些對象佈局,渲染順序等功能)

我們向APE引擎加入了很多對象,這會導致每1/60秒渲染一幀變慢。請記住: 就拿Quake 3來說,也不能在大部分機器上達到每秒60幀的速度。

package {
     import Flash.display.*;
     import org.cove.ape.*;

     [SWF(backgroundColor="#115A70", frameRate="60")]
     public class CarDemo extends Sprite {

          public function CarDemo() {
               stage.scaleMode = StageScaleMode.NO_SCALE;
               stage.align = StageAlign.TOP_LEFT;
               APEngine.init(1/4);
               APEngine.container = this;
               APEngine.addMasslessForce(new Vector(0,1));

               stage.addEventListener(Event.ENTER_FRAME, run);
          }

          private function run(e:Event): void {
               APEngine.step();
               APEngine.paint();
          }
     }
}

現在,我們編譯程序,並運行。如果你沒有得到任何錯誤,那你就已經創建了自己的物理世界了,看,這是多麼的簡單!

接下來,我們將創建3個表面,更多的牆和門。記住我們爲所有不是牆的對象都設置重力。

現在我們創建一個新的類,叫Surface.as。  這個類將作爲APE引擎擴展的一部分。APE Group類的目的是幫助我們更容易地管理這些對象。如果我們繼承了Group類,那我們就可以在一個類文件中加入所有的表面,從而使得所有的對象都在一起維護。

package outsider{
     import Flash.display.*;
     import org.cove.ape.*;

     public class Surface extends Group {

          public function Surface(collideInternal:Boolean=false)  {
               super(collideInternal);       
          }
     }
}

我們下一個目標是創建一個矩形來作爲表面。矩形和圓是APE引擎的核心對象。所有加入到APE中的對象都是粒子(particle)。編碼非常簡單,你只需要設置粒子的x, y座標, 長度, 高度,旋轉弧度即可。 如果引擎返回true, 則表示已經固定了粒子。如果一個對象固定了,則它總是保持靜態的。重力(gravity)和碰撞(collision)隻影響移動對象。因爲我們繼承了Group類,這意味Surface類也可以增加粒子。

package outsider{
     import Flash.display.*;
     import org.cove.ape.*;

     public class Surface extends Group {

          public function Surface(collideInternal:Boolean=false) {
               super(collideInternal);     
               var lineThickness:int = 1;
               var lineColor:uint = 0xffffff;
               var fillColor:uint = 0xffffff;

               var leftWall:RectangleParticle = new RectangleParticle(10, 200, 20, 400, 0, true);
               leftWall.setStyle(lineThickness, lineColor, 1, fillColor, 1);
               addParticle(leftWall);

               var floor:RectangleParticle = new RectangleParticle(405, 400, 800, 20, 0, true);
               floor.setStyle(lineThickness, lineColor, 1, fillColor, 1);
               addParticle(floor);

               var rightWall:RectangleParticle = new RectangleParticle(800, 200, 20, 400, 0, true);
               rightWall.setStyle(lineThickness, lineColor, 1, fillColor, 1);
               addParticle(rightWall);
          }
     }
}

現在,我們再回到CarDemo類,並增加Surface類到這個Demo中。這樣我們的Demo將會顯示這小表面。代碼如下:

package {
     import Flash.display.*;
     import org.cove.ape.*;
     import outsider.*;

     [SWF(backgroundColor="#115A70", frameRate="60")]
     public class CarDemo extends Sprite {

          public function CarDemo() {
               stage.scaleMode = StageScaleMode.NO_SCALE;
               stage.align = StageAlign.TOP_LEFT;
               APEngine.init(1/4);
               APEngine.container = this;
               APEngine.addMasslessForce(new Vector(0,1));

               var surface:Surface = new Surface();
               APEngine.addGroup(surface);

               stage.addEventListener(Event.ENTER_FRAME, run);
         }

         private function run(e:Event): void {
              APEngine.step();
              APEngine.paint();
         }
     }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章