使用四叉樹優化碰撞檢測
阿新 • • 發佈:2020-06-18
# 四叉樹是幹什麼的?
百度百科
四元樹又稱四叉樹是一種樹狀資料結構,在每一個節點上會有四個子區塊。四元樹常應用於二維空間資料的分析與分類。 它將資料區分成為四個象限。資料範圍可以是方形或矩形或其他任意形狀。
從定義我們可以看出重點資訊:
1. 樹狀結構
2. 四個區塊
3. 分類
4. 矩形
# 圖示講解
講解之前需要先說明一下四叉樹是用來做什麼的,明白了原理才好理解它的行為。
使用四叉樹就是使用分類的方法,減少碰撞節點的個數,只取出與給定碰撞體相同區域或者壓在碰撞體所在區域邊上的物件。
1. 將遊戲螢幕分為四個區域。
![916005-20160612193213793-1006655096.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122654653-169438098.png)
2. 插入物件
![916005-20160612193357043-1288525697.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122654789-1280790080.png)
3. 插入的物件超過了我們設定的閾值時,劃分
![916005-20160612193417902-1220978536.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122654970-601508908.png)
4. 插入的物件再次超過了我們設定的閾值時,繼續分。
![916005-20160612193502902-1720204858.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122655122-1586427728.png)
# 分析
## 插入
從上面的圖示我們可以很好理解四叉樹的原理。涉及的都是插入操作。
那麼插入操作具體都做了什麼呢?
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122655447-888035018.png)
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122655734-716086276.png)
從程式碼中我們可以看出:
1. 當插入第一個物件的時候只走了2;這個時候沒有子樹,所以不會走1,因為objects(管理的物件)的長度還沒有超過我們設定的閾值MAX_OBJECTS,所以也不會走3。
2. 一直插入,當objects中的數量,超過了我們設定的閾值MAX_OBJECT,就會開始劃分,產生子樹,有了nodes,劃分之後將自己管理的節點插入到子樹中。再此之前,都不會走1,因為還沒有產生子樹。
3. 劃分之後再次插入新物件,如果物件可以獲得對應的象限,就會走1 不會走2和3,如果沒有獲得對應的象限才會走2,3(沒有獲得的情況可能是你建立的物件在螢幕外,遊戲中很多情況是敵人從螢幕外走進螢幕的,具體可參考我做的《星際迷航》或者《星際戰》遊戲)。
## 更新物件
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122655987-1473110082.png)
我是把四插入作為了物件管理器使用,要不然物件也需要更新,所以有了這一步操作。如果不這樣你需要自己建立物件管理器,一個一個放進去,刪除。通過四叉樹直接管理省了不少事情。
## 更新象限資訊。
這是一個遞迴操作,更新象限做的事情比較多了。
1. 檢查物件是否存活,如果死亡就回收,我這裡使用了物件池,所以物件實現了poolAble介面。
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122656310-1867840944.png)
2. 判斷物件的所佔區域是否在四叉樹的區域內
這裡需要說明的是一個四叉樹本身的區域是它管理的四個象限這麼大。也就是一個四叉樹管理四個象限
![83792-20170717120708910-531711251.jpg](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122656611-1333526666.jpg)
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122656817-312414878.png)
不在管理區域的話需要判斷當前this是否為根節點,如果是說明物件已經出屏了。(這個時候可以通過物件實現的isVisible介面來控制是否回收,因為不是所有在螢幕外的都要回收,比如要進入螢幕的敵人,是不可能回收的,所以需要自己用isVisible介面來控制)。如果不是就將物件放入根節點,重新劃分。
3. 在管理區域內,就看看在四叉樹管理的哪個象限裡。更新象限資訊。
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122657018-2008518944.png)
如果沒有變化什麼都不過,如果有變化,先判斷象限是否為-1,為什麼會出現-1,也就是不在四個象限的任何一個象限?因為壓線了。此番操作後的結果如下圖。
![83792-20170717120718847-65956331.jpg](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122657238-1348428938.jpg)
## 根據給定矩形獲取物件列表
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122657460-1952698317.png)
1. 第一個是步長,用於獲取深度,當然深度越長,處理的時間越長,獲取的物件也精細。這個可以根據自己遊戲的同屏四叉樹層級而定了。
2. 如果通過obj的rect獲得物件所在象限如果獲得了對應的象限,用獲得的象限的四叉樹再獲取。如果壓線的話就需要將碰撞的兩個象限的內容都取出來。
3. 返回四叉樹中沒有分割象限的物件。
# 怎麼用呢?
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122657785-2112875331.png)
自然就是把要碰撞的物件傳給retrieve函式獲得需要碰撞的物件列表進行碰撞檢測了。
也就是文章靠頭說的:
使用四叉樹就目的是為了減少碰撞節點的個數。使用的是分類的方法。
至於用什麼樣的碰撞檢測函式,不是四叉樹關心的事情,
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122658052-569023792.png)
至於用幾個四叉樹管理物件,也不是四叉樹關心的事情。
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122658217-1684203810.png)
# 結語
想要demo的同學可以去我的微店或者官方creator商城購買《跨引擎遊戲框架》原始碼,跟demo是一個專案。買過的同學請加我好友,群已經建好,有更新我會群裡直接發包。
原始碼購買入口:
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122658363-1573548655.png)
demo展示:
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122700544-967770415.png)
專案截圖:
![image.png](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122702328-1598912117.png)
框架的相關模組教程可以到《我的專輯》遊戲開發進階教程中獲取。
後續還會推出更多與框架有關的教程:如:戰鬥框架,教學框架等等。並附帶完整的遊戲實現(飛行射擊遊戲為例,學會做飛行射擊遊戲不是目的,目的是通過這一款遊戲,你可以獲得做其他所有型別的遊戲的思路)。希望可以在不餓死自己的前提下幫助更過的朋友們快速找到開發思路。
長按下方二維碼,關注《微笑遊戲》公眾號,獲取更多精彩內容。
![image](https://img2020.cnblogs.com/other/330473/202006/330473-20200618122702578-394609198.webp)
歡迎掃碼關注公眾號《微笑遊戲》,瀏覽更多內容。