第38節 - LibGDX: Tiled (Collision Detection)
這一節我會介紹LibGDX遊戲的Collision Detection System,我在第36節 - LibGDX: Tiled Map Editor (Background & Foreground)介紹過如何利用Tiled Map Editor製造一張foreground Map Layer,再在foreground上加上"blocked" properties。
一個2D Platformer Game遊戲的Collision Detection System主要包括以下部分:
- Right Collision
- Left Collision
- Bottom Collision
- Top Collision
製作Foreground (Set properties = "blocked")
以下設有紅色邊的tile(方塊)就須要把properties加上"blocked",詳細介紹請看第36節 - LibGDX: Tiled Map Editor (Background & Foreground):
執行結果:
以下是LibGDX: Tiled (Collision Detection)程式執行的結果:
Collision Detection主要部分介紹
1) Cell & Tile的分別
在Tiled的Map內,有不同的Layer,而每一層Layer內,就有不同的格子(Tile),為甚麼還有Cell? Cell也是一個類別,它是TiledMapTileLayer類別的static Inner Class,Cell類別把Tile物件(tile)傳入,因為Cell類別有很多不同的方法可以用在Tile物件(tile)上,例如: getTile 、setTile、getFlipHorizontally()、setFlipHorizontally、 getFlipVertically、 setFlipVertically、 getRotation()和 setRotation()等等,如下圖:
以下是LibGDX的官方解釋:
A cell is a container for a TiledMapTile. The cell itself stores a reference to a tile in addition to attributes that specify if the tile should be rotated or flipped when rendering it.
2) Tile Coordinate System
- 以上是Tile的座標系統,座標(0,0)設定在左下角。
3) 建立isCellBlocked() Method
- 建立一個isCellBlocked()方法,把tile的座標傳入。
- 注意,傳入tile的座標後,我們用getCell()方法取得tile座標的(x,y)值,(x,y)值必須是int type。
例如: int(2.35) = 2,int(2.999) = 2等等。 - 我們在foreground Layer內只建立以上紅色邊的tile,其他沒有紅色邊的tile不是tile!,所以會return null。
- 用Cell類別的cell.getTile().getProperties(0.constantKeys()方法,偵測tile是否有"blocked" properties。
Right Collision
- 建立一個collisionRight()方法,偵測右手面的兩個tile是否有"blocked" properties。
- 因為主角(hero1)是面向右手面,所以偵測的兩點須要加上64px。
- 例如主角(hero1)的座標是(0,0),兩個tile的座標便會是(2,2)和(2,1)。
- 注意,因為主角(hero1)企立的位置是用collisionBottom()方法偵測後計算出來,(hero1)企立的位置不一定是(0, 32, 64, 96....的整數),所以就會有小小偏差(大約2px)。
就是這小小偏差(大約2px),偵測的兩個tile的座標便會向下移一格,我會在其他章節介紹準確計算座標的方法。
Left Collision
- 建立一個collisionLeft()方法,偵測左手面的兩個tile是否有"blocked" properties。
- 因為主角(hero1)是面向左手面,所以偵測的兩點須要減少5px。
- 例如主角(hero1)的座標是(160,0),兩個tile的座標便會是(4,2)和(4,1)。
- 注意,因為主角(hero1)企立的位置是用collisionBottom()方法偵測後計算出來,(hero1)企立的位置不一定是(0, 32, 64, 96....的整數),所以就會有小小偏差(大約2px)。
就是這小小偏差(大約2px),偵測的兩個tile的座標便會向下移一格,我會在其他章節介紹準確計算座標的方法。
Bottom Collision
- 建立一個collisionBottom()方法,偵測左手面兩個tile是否有"blocked" properties。
- 偵測右手面兩個tile是否有"blocked" property。
注意,右手面和右手面偵測的座標有所不同,是因為我們勿須偵測主角(hero1)最背後位置的tile是否有"blocked" properties,如果沒有,代表主角(hero1)是企在空氣中,主角(hero1)便會下降。
- 例如主角(hero1)的座標是(128,64),兩個tile的座標便會是(5,2)和(6,2)。
- 注意,因為主角(hero1)企立的位置是用collisionBottom()方法偵測後計算出來,(hero1)企立的位置不一定是(0, 32, 64, 96....的整數),所以就會有小小偏差(大約2px)。
就是這小小偏差(大約2px),偵測的兩個tile的座標便會向下移一格,我會在其他章節介紹準確計算座標的方法。
- 例如主角(hero1)的座標是(128,64),兩個tile的座標便會是(4,2)和(5,2)。
- 注意,因為主角(hero1)企立的位置是用collisionBottom()方法偵測後計算出來,(hero1)企立的位置不一定是(0, 32, 64, 96....的整數),所以就會有小小偏差(大約2px)。
就是這小小偏差(大約2px),偵測的兩個tile的座標便會向下移一格,我會在其他章節介紹準確計算座標的方法。
Top Collision
- 建立一個collisionTop()方法,偵測頭頂一個tile是否有"blocked" properties就足夠。
- 偵測頭頂一個tile是否有"blocked" properties。
- 例如主角(hero1)的座標是(128,0),兩個tile的座標便會是(5,2)。
- 注意,這次因為是在空中偵測頭頂的座標,小了(大約2px)後,便會回復正確的tile。
LibGDX程式
例子1 - 2D Platformer Game with Collision Detection
這個例子會用LibGDX示範Collision Detection System:
DesktopLauncher.java
- DesktopLauncher是PC Desktop的Starter Class,我們在DesktopLauncher內設定顯示的大小為1024 X 768 px。
- 把hero1Atlas.pack和hero1Atlas.png儲存到Android的Assets文件夾內(/data/...)。
- 把map.tmx和tileAtlas.png儲存到Android的Assets文件夾內(/map/...)。
MyDemo38.java
- 建立collisionRight, collisionLeft, collisionBottom和collisionTop變數(Variable)。
- 建立一個TiledMapTileLayer的物件(foregroundLayer),並把foreground Layer傳入。
- 建立Collision Detection System的方法:
1) isCellBlocked()
2) collisionRight()
3) collisionLeft()
4) collisionBottom()
5) collisionTop()
- 設定State.Walking動作,Walking動作須要偵測以下方向:
1) collisionRight()
2) collisionLeft()
3) collisionBottom()
- 設定State.Jumping動作,Jumping動作須要偵測以下方向:
1) collisionTop()
2) collisionBottom()