解碼mmo遊戲服務器三:大地圖同步(aoi)

問題引入:aoi(area of interest).在大地圖中,玩家只須要關心本身周圍的對象變化,而不須要關心距離較遠的對象的變化。因此大地圖中的數據不須要所有廣播,只要同步玩家本身視野範圍的消息便可。git

解決方案:github

1:燈塔法。golang

所謂燈塔法,即將大地圖劃分紅有限的小格子,在每一個小格子中間放一個燈塔,這個燈塔管理兩個隊列:一個是本格子內全部的對象集合,另外一個是對本燈塔感興趣的對象集合(簡稱觀察者)。3d

而地圖上的每一個對象,維護一個視野隊列:該隊列爲其視野範圍內的全部對象,即自身感興趣的全部對象。rest

一個對象在地圖上面運動:分爲三個操做:enter,move,leave.對象

enter:當對象進入地圖的時候,根據對象的當前位置和對象的感知距離,能夠獲取到該對象能觀察到的全部燈塔,遍歷這些燈塔,將該對象添加爲其觀察者。同時將這些對象添加到本身的視野隊列中。隊列

move:當對象開始移動的時候,對象從一個點到另外一個店,那麼視野範圍必然發生變化。此刻須要將對象從老的燈塔的觀察者列表移除,同時將對象添加進新的燈塔的觀察者列表。此外,還須要跟新玩家的視野隊列,由於視野範圍變化,視野內的對象也相應變化。遊戲

leave:當對象離開的時候,將自身從附近燈塔的觀察者隊列中移除。內存

經過燈塔法,每當物體發生變化,咱們能立刻根據其當前位置,定位到他的所在的燈塔,同時找到它視野範圍內相關聯的物體。這樣避免了遍歷地圖上全部玩家進行處理的方式。同步

固然燈塔的格子大小劃分要因地制宜,格子越小,消耗內存越大,同時計算量變大。

2: 九宮格

九宮格也是打格子的方式之一,把地圖劃分爲不少小格子,每一個格子記錄格子內的玩家,每一個玩家的aoi範圍是以本身爲中心範圍內的九個格子,九個格子的大小略大於屏幕大小,一樣的有三個主要的操做:enter,move,leave

enter:根據玩家座標,加入到所屬的格子中,經過計算以這個格子的爲中心的九個格子,這九個格子內的玩家就要被通知有新玩家初始化,同時這個新玩家初始化九個格子內的全部玩家。

move:根據移動前位置的格子,計算出移動前的oldaoi集合,根據當前位置的格子,計算出當前的curaoi集合,若是oldaoi, curaoi爲同一個格子,則通知格子內的全部玩家該玩家在移動。若是oldaoi,curaoi不是同一個格子,即發生了跨格子的操做,那麼要將該玩家從舊格子移除,同時加入新格子。同時分別遍歷oldaoi,curaoi,計算出須要通知玩家消失的格子集合,通知玩家出生的格子集合,以及通知玩家移動的格子集合。

leave:玩家離開地圖,將玩家從對應的格子裏面刪除,同時通知aoi集合有玩家離開。

3:十字鏈表法

這裏以2d遊戲爲例,3d遊戲順勢擴展便可。

所謂十字鏈表法,即維護兩天鏈表,一條根據地圖上全部物體的x座標從小到大依次插入鏈表,一條根據地圖上全部物體的y座標從小到大依次插入鏈表,能夠想象成一個十字架。這樣便把地圖上的全部對象按序分配到了x,y鏈表上。

這裏的鏈表爲雙向鏈表,雙向鏈表的好處是,獲取到鏈表中的一個節點,即可以向前和向後遍歷。這樣,當咱們拿到一個對象時,要獲取該對象的視野範圍就變得很是簡單。避免了從頭至尾遍歷全部對象。

首先根據x座標,在x鏈表上找到該節點,而後從該節點向前和向後遍歷,根據x方向的視野範圍找出須要識別的對象。

而後根據y座標,在y鏈表上找到該節點,而後從該節點向前和向後遍歷,根據y方向的視野範圍找出須要識別的對象。

拿到x,y鏈表上須要關注的對象,而後取他們的交集,這即是玩家視野範圍內的對象。

對於對象在地圖上的enter,move,leave 。根據前面的思路就變得很是簡單

對應的golang 九宮格實現:https://github.com/yyhero/gridview

相關文章
相關標籤/搜索