7.1Box2D概述
Box2D是一款用于2D游戲的物理引擎。在Box2D物理世界里,創建出的每個物體都更接近于真實世界中的物體,讓游戲中的物體運動起來更加真實可信,讓游戲世界看起來更具交互性。 Android平臺常見的十幾款游戲引擎中,例如:Rokon、AndEngine、libgdx等物理引擎都封裝了Box2D物理引擎,可見Box2D在物理引擎中占據了多重要的位置。
Box2D在很多平臺都有對應的版本:Flash版本、Iphone版本、Java版本(JBox2D)等等,在本書中開發Android語言采用的是Java,所以這里介紹的對應Box2D平臺也是Java平臺,稱為JBox2D,對應的版本為JBox2d 2.0。
7.2將Box2D類庫導入Android項目中
添加Box2D類庫到Android項目詳細步驟如下:
新建項目“HelloBox2d”(創建Android項目與之前創建項目步驟無差異)。
然后在項目里添加一個“lib”目錄用于存放Box2D類庫(“.jar”)。
右鍵項目“HelloBox2d”,選中“New”→“Folder”選項,然后出現“New Folder”窗口,如
圖7-1所示。
圖7-1 New Folder
圖7-1所示的窗口中,在“Folder name”文本框中填寫目錄名,這個目錄名可以自定義,一般導入外部類庫目錄都使用lib與libs來命名,然后單擊“Finish”按鈕完成目錄的創建。
此時只是將Box2D提供的類庫放入Android項目中,但是并沒有添加到項目的類庫中,所以還需要將Box2D包添加到項目類庫中!
右擊項目“HelloBox2d”選中“Properties ”→“Java Build Path”→“Libraries”→“Add
<”,選中“HelloBox2d”項目下lib目錄下的Jbox2d類庫的jar包,最后一直單擊
“OK”按鈕返回即可,如圖7-2、圖7-3所示。
圖7-2 項目配置
圖7-3 項目中添加Box2d類庫
到此,在Android項目中添加JBox2D物理引擎類庫的步驟就結束了,現在就開始進入Box2D引擎的物理世界吧!
7.3物理世界與手機屏幕坐標系之間的關系
本節來講解一下物理世界與手機屏幕坐標系之間的關系。假設創建一個200米的物理世界,然后觀察其物理世界與手機屏幕之間的坐標系關系,如圖7-4所示。
圖7-4 物理世界與手機屏幕坐標系關系圖
從圖7-4中可以很清晰的看出,手機屏幕的左上角(0,0)坐標,正是物理世界的中心點坐標;手機屏幕繪制圖形時,一般默認以左上角作為錨點!而在Box2d的物理世界中,一個新的Body(物體)等被創建出來之后,默認以其質心(可以近似為中心點)作為錨點;如圖7-5所示,是“在屏幕上繪制一張圖片,并且在物理世界中添加一個物體”的位置關系圖。
圖7-5 默認放置的位置對比圖
除此之外,Box2D為了使物體與關節等更加貼切的模擬現實,在Box2D引擎中使用的長度單位是“米(m)”,所以Box2D引擎中的一些方法的長度參數不再是以像素為單位,而是需要轉換成“米”;反之,從Box2D引擎函數返回值中得到的長度值也是以“米”做單位的,使用其值前需要將其轉換為像素,然后再使用。
關于米與像素之間的換算關系,其實是通過自定義一個現實與屏幕的比例關系進行換算的,后續章節會有講解。
7.4創建Box2D物理世界
World(jbox2d.dynamics.World)類就是Box2D引擎中的物理世界。不管是Body(物體)還是Joint(關節)都必須放在Box2D這個物理世界中,因為物理世界也是有范圍的,一旦物體和關節不在世界范圍內,它們將不會進行物理模擬。
下面就來創建一個物理世界,范例項目對應的源代碼為“7-4(Box2d物理世界)”。
首先看一下World類的構造函數:
World(AABB world AABB,Vec2 gravity,boolean doSleep)
World類只有這一種構造方式,它的三個參數的含義如下:
l 第一個參數:AABB類的實例,AABB表示一個物理模擬世界的范圍;
l●第二個參數:Vec2實例,一個二維世界向量類,在Box2D中的最常用的一種數據類型;在這里表示物理世界的重力方向;
l●第三個參數:布爾值,表示在物理世界中,如果靜止不動的物體是否對其進行休眠。
如果設置其值為“true”,則表示當物理世界開始進行模擬時,在這個物理世界中靜止沒有運行的物體都將進行休眠,除非物體被施加了力的作用或者與其他物體發生碰撞之后會被喚醒;如果設置其值設置為“fal”,那么物理世界中的所有物體不管是否靜止都會一直進行物理模擬。
創建一個物理世界代碼如下:
AABB aabb = new AABB();// 實例化物理世界的范圍對象
aabb.lowerBound.t(-100, -100);// 設置物理世界范圍的左上角坐標
aabb.upperBound.t(100, 100);// 設置物理世界范圍的右下角坐標
Vec2 gravity = new Vec2(0, 10);// 實例化物理世界重力向量對象
World world = new World(aabb, gravity, true);// 實例化物理世界對象
以上代碼中有兩點需要注意:
(1)aabb設置物理世界范圍傳入的參數,不要理解成像素!在Box2d的物理世界中,被認為是現實生活中的“米(m)”單位。
(2)設置物理世界的重力向量(gravity),其兩個參數在這里分別表示物理世界中的X軸與Y軸方向上的重力數值,其值的“+”“?”號在這里表示X與Y軸的重力方向,X軸正值表示向右,Y軸正值表示向下;因為是模擬真實世界,所以這里的X重力向量設置為零,Y 軸方向設置為現實生活中的重力值:10(可以理解為10N)。
剛才的一段代碼就已經創建了一個物理世界,但只是定義了物理世界,并沒有開始進行物理模擬,所以還需要world設置物理模擬:
world.step(float timeStep, int iterations);
此函數表示讓物理世界開始進行物理模擬,其兩個參數含義如下:
l●第一個參數:表示(時間步)物理世界模擬的頻率;
l●第二個參數:表示(迭代值)迭代值越大模擬越精確,但性能越低。
這里要注意以下幾點:
①因為物理世界模擬具有持續性,所以應該將設置放在線程中,不斷的讓物理世界進行模擬。
②時間步:應該與游戲的刷新率相同,否則物理世界模擬將不同步。
③迭代值:可以理解為在單次時間步中進行遍歷模擬運算數據的次數。
④在Box2D中最常使用的單位是float浮點數類型,作者剛接觸Box2D時,在定義物理世界模擬頻率時,寫成了以下錯誤的形式: