燈塔AOI簡易實現

首先咱們來討論下游戲開發中的幾個座標系,爲了方便解釋,我截取了燈塔AOI DEMO當NPC數目爲0時候的樣子(代碼地址以爲有幫助的童鞋記得給我代碼點個星^_^)git

先對這張圖簡單說明下:github

  • 藍色的座標軸表示是燈塔AOI座標系,綠色的座標軸表示的是遊戲座標系,向左爲X軸正方向,向上爲Y軸正方向(這個座標是我本身後面畫上去的)
  • 深藍色的點表示燈塔AOI座標,左下的表示(0,0),右上表示(1,1)
  • 深綠色的點表示遊戲座標,左下表示(0,0),右上表示(1,1)
  • 每一個灰色的小格子表明一個遊戲座標(邊長爲15像素)
  • 每一個黃灰的大格子表明一個燈塔AOI座標(邊長爲11個灰色小格子)
  • 瓦片地圖大小爲寬:100個灰色小格子 高:70個灰色小格子
  • 深藍色的方塊爲玩家,大紅色方框爲玩家在遊戲座標系中的視野(視野半徑爲10個灰色小格子),蘭色方框表示玩家在燈塔座標系中的視野

像素

這個是客戶端圖形實際顯示要用到的座標(和遊戲邏輯無關),每一個圖片長寬各多少像素,描點在什麼位置,可是在遊戲中直接使用像素做爲計量單位(座標點)十分不方便,好比物體的移動,何況移動也不會一個像素一個像素移動,因此咱們作了一層抽象(格子),遊戲相關的貼圖(地圖/人物/道具)必須是格子的整數倍,這樣遊戲中全部的物體才能被正常顯示,而不會產生誤差。code

格子/瓦片(遊戲座標系)

什麼是格子?格子是遊戲邏輯使用的最小單位,表明遊戲座標系的點,它的單位爲像素(DEMO中15*15像素爲一格),遊戲中全部設定都必須是格子的整數倍,因此不會出現有物體在兩個格子之間,致使座標不肯定的狀況,物體的移動的步長單位也變成多少格,而不是像素了,即若是使用像素做爲座標點,從(0,0)移動到(0,1),則移動了1個像素,如今用格子做爲座標點,從(0,0)移動到(0,1),則移動了15個像素。對象

什麼是瓦片?一張大的世界地圖或者背景圖能夠由幾種地形來表示,每種地形對應一張小的的圖片,咱們稱這些小的地形圖片爲瓦片。把這些瓦片拼接在一塊兒,一個完整的地圖就組合出來了,這就是瓦片地圖。blog

在DEMO中,爲了簡化邏輯,我將瓦片設置爲一倍格子大小,玩家和NPC的大小也設置爲一倍格子大小。遊戲

燈塔AOI座標系

爲何須要燈塔AOI?假設咱們想知道某點周圍10格內有哪些對象,在沒有燈塔AOI的狀況下,咱們須要遍歷全部的對象計算其是否在範圍內,隨着地圖內的對象愈來愈多,查找的效率也會愈來愈差,因此咱們須要一種方法來過濾那些明顯不須要參與計算的對象,因此咱們將地圖分割成一個個區域,在其中心放置一個假想的"燈塔",每一個"燈塔"都會保存區域內的對象,這樣當咱們須要知道某點周圍10格內有哪些對象時,咱們只須要計算出範圍內有哪些"燈塔",而後獲取這些"燈塔"保存的對象列表,針對這些對象進行計算就能節省大量計算。爲了方便表示和管理這些"燈塔",咱們爲其分配了新座標(左下爲(0,0)),這個新的座標系即燈塔AOI座標系(這個座標系是用來作碰撞檢測的)圖片

燈塔視野和玩家視野

"燈塔"的視野越小,在碰撞檢測時能過濾的無效對象就越多,可是整張地圖"燈塔"的數目也就越多,消耗的內存就越大,並且對象進出燈塔的計算量就越多內存

"燈塔"的視野越大,在碰撞檢測時能過濾的無效對象就越少,碰撞檢測的計算量就越大,想象下只有一個"燈塔"的狀況,即退回了沒有燈塔AOI系統的狀況遊戲開發

因爲玩家的視野通常是固定的(屏幕顯示區域大小通常固定),因此燈塔視野大小通常是玩家視野的1/2或1/3比較合適開發

燈塔座標的計算

假設要計算遊戲中某點所處的燈塔座標(詳細邏輯見代碼註釋):

### 將遊戲座標系和燈塔AOI座標系對齊,而後除以燈塔邊長(兩倍視野內包含的格子數 + 自身座標格子)
static_cast<int>(std::floor(static_cast<float>(遊戲X座標 - 遊戲地圖左下角原點X座標)  /  (2  *  "燈塔"視野  +  1))
static_cast<int>(std::floor(static_cast<float>(遊戲Y座標 - 遊戲地圖左下角原點Y座標)  /  (2  *  "燈塔"視野  +  1))

燈塔AOI邏輯

對象進入(角色登入、生成怪物):

  • 根據對象座標計算對象所屬燈塔,將對象添加到燈塔的對象列表,若是燈塔上綁定了觀察者,則通知觀察者有對象進入
  • 找出對象視野範圍的燈塔,將自身綁定爲其觀察者,綁定燈塔會將自身現有對象列表發送給對象

對象離開(角色登出、怪物被殺死):

  • 根據對象座標計算對象所屬燈塔,將對象從燈塔的對象列表中移除,若是燈塔上綁定了觀察者,則通知觀察者有對象離開
  • 找出對象視野範圍的燈塔,解除其觀察者綁定,解除綁定燈塔會將自身現有對象列表發送給對象

對象移動

  • 若是對象所屬燈塔沒變,則不作任何操做
  • 若是對象所屬燈塔改變,則對舊燈塔執行對象離開邏輯,對新燈塔執行對象進入邏輯,可是要注意的是對視野的處理,先後視野交集內的燈塔不須要執行解綁和綁定操做
相關文章
相關標籤/搜索