最近在做一個移動平台上的MMORPG項目,負責服務器的工作,第一次做這種類型的游戲服務器的開發,准備工作時必須的,綜合網上的資料和自己的想法,總結了一下AOI的實現方式,從以下三個方面來談談。水平有限,本文提出的實現方式可能會很笨拙,但是應付一般的場景還是可以的。
1、關於怪物主動攻擊玩家的檢測
如果場景內有N個怪物,M個玩家,則進行一次檢測需要計算N*M次玩家和怪物之間的距離,這種方法很笨。一種新的方式是:首先對游戲的場景進行一下划分,如下圖,將場景划分成若干個格子,每個網格擁有唯一編號gridId,白色星代表當前玩家的位置,紅色網格代表玩家所在的網格區域黃色的為8個臨近區域,服務器為每個網格對象維護兩個列表:monsterList和playerList,這兩個列表記錄了在當前網格中的怪物和玩家。
當玩家進入場景后,將玩家當前所在的網格id(curGridId)設置為紅色網格的gridId,將周圍的8個黃色網格的gridId放入玩家的adjacentGridList中。具體的怪物攻擊檢測流程:
這樣處理的好處有:
(1) 只有當玩家移動時才會進行怪物主動攻擊玩家的檢測。避免了不必要的檢測;
(2) 減少了計算怪物和玩家距離的次數,如一開始所述,如果場景內有N個怪物,M個玩家,則進行一次檢測需要計算N*M次距離。該方法首先在場景更新線程中判斷玩家是否從網格g1進入網格g2,判斷時會與周圍8個格子的中心點計算,最差的情況是計算8次,但是此處也可以優化,如果知道玩家的移動向量,則只進行一次計算就可以確定玩家是否跨越了格子。怪物攻擊玩家檢測線程中,只計算玩家當前所在的格子中的怪物與玩家的距離,計算次數為(假設每個格子中怪物和玩家平均分布):(N/格子數量)*(M/格子數量)。
2、怪物移動控制
游戲中會單獨啟動一個線程(T_MonsterMove)去執行怪物移動的操作,該線程屬於定時線程,以1秒或更短的頻率根據怪物的類型更新怪物的位置。並將移動后怪物的坐標信息發送給客戶端,T_MonsterMove線程並不需要和主邏輯線程進行同步操作,因為T_MonsterMove線程中移動的怪物都是處於服務器托管的,怪物主動攻擊線程檢測到玩家進入怪物攻擊范圍后,會將該怪物從服務器托管列表中移除,交由客戶端托管。
3、怪物和玩家移動等信息的廣播范圍
在游戲中,我們把格子的大小定義為玩家360度視野的范圍。adjacentGridList保存的是玩家相鄰的8個格子id和curGridId保存的是當前玩家所在的格子的id。以玩家移動信息為例,只需要將消息發送給這9個格子中的玩家即可。將信息發送給相鄰的8個格子的玩家可以避免玩家突然閃進視野的情況發生。