小談Online-game服務器端設計(3)

下面我想來談談關于服務器上NPC的設計以及NPC智能等一些方面涉及到的問題。首先,我們需要知道什么是NPC,NPC需要做什么。NPC的全稱是(Non-Player Character),很顯然,他是一個character,但不是玩家,那么從這點上可以知道,NPC的某些行為是和玩家類似的,他可以行走,可以戰斗,可以呼吸(這點將在后面的NPC智能里面提到),另外一點和玩家物件不同的是,NPC可以復生(即NPC被打死以后在一定時間內可以重新出來)。其實還有最重要的一點,就是玩家物件的所有決策都是玩家做出來的,而NPC的決策則是由計算機做出來的,所以在對NPC做何種決策的時候,需要所謂的NPC智能來進行決策。
  下面我將分兩個部分來談談NPC,首先是NPC智能,其次是服務器如何對NPC進行組織。之所以要先談NPC智能是因為只有當我們了解清楚我們需要NPC做什么之后,才好開始設計服務器來對NPC進行組織。
NPC智能
  NPC智能分為兩種,一種是被動觸發的事件,一種是主動觸發的事件。對于被動觸發的事件,處理起來相對來說簡單一些,可以由事件本身來呼叫NPC身上的函數,比如說NPC的死亡,實際上是在NPC的HP小于一定值的時候,來主動呼叫NPC身上的OnDie() 函數,這種由事件來觸發NPC行為的NPC智能,我稱為被動觸發。這種類型的觸發往往分為兩種:
一種是由別的物件導致的NPC的屬性變化,然后屬性變化的同時會導致NPC產生一些行為。由此一來,NPC物件里面至少包含以下幾種函數:
class NPC {
public:
??? // 是誰在什么地方導致了我哪項屬性改變了多少。
??? OnChangeAttribute(object_t *who, int which, int how, int where);
Private:
??? OnDie();
??? OnEscape();
??? OnFollow();
??? OnSleep();
??? // 一系列的事件。
}
  這是一個基本的NPC的結構,這種被動的觸發NPC的事件,我稱它為NPC的反射。但是,這樣的結構只能讓NPC被動的接收一些信息來做出決策,這樣的NPC是愚蠢的。那么,怎么樣讓一個NPC能夠主動的做出一些決策呢?這里有一種方法:呼吸。那么怎么樣讓NPC有呼吸呢?
  一種很簡單的方法,用一個計時器,定時的觸發所有NPC的呼吸,這樣就可以讓一個NPC有呼吸起來。這樣的話會有一個問題,當NPC太多的時候,上一次NPC的呼吸還沒有呼吸完,下一次呼吸又來了,那么怎么解決這個問題呢。這里有一種方法,讓NPC異步的進行呼吸,即每個NPC的呼吸周期是根據NPC出生的時間來定的,這個時候計時器需要做的就是隔一段時間檢查一下,哪些NPC到時間該呼吸了,就來觸發這些NPC的呼吸。
  上面提到的是系統如何來觸發NPC的呼吸,那么NPC本身的呼吸頻率該如何設定呢?這個就好象現實中的人一樣,睡覺的時候和進行激烈運動的時候,呼吸頻率是不一樣的。同樣,NPC在戰斗的時候,和平常的時候,呼吸頻率也不一樣。那么就需要一個Breath_Ticker來設置NPC當前的呼吸頻率。
  那么在NPC的呼吸事件里面,我們怎么樣來設置NPC的智能呢?大體可以概括為檢查環境和做出決策兩個部分。首先,需要對當前環境進行數字上的統計,比如說是否在戰斗中,戰斗有幾個敵人,自己的HP還剩多少,以及附近有沒有敵人等等之類的統計。統計出來的數據傳入本身的決策模塊,決策模塊則根據NPC自身的性格取向來做出一些決策,比如說野蠻型的NPC會在HP比較少的時候仍然猛撲猛打,又比如說智慧型的NPC則會在HP比較少的時候選擇逃跑。等等之類的。
  至此,一個可以呼吸,反射的NPC的結構已經基本構成了,那么接下來我們就來談談系統如何組織讓一個NPC出現在世界里面。
NPC的組織
  這里有兩種方案可供選擇,其一:NPC的位置信息保存在場景里面,載入場景的時候載入NPC。其二,NPC的位置信息保存在NPC身上,有專門的事件讓所有的NPC登陸場景。這兩種方法有什么區別呢?又各有什么好壞呢?
  前一種方法好處在于場景載入的時候同時載入了NPC,場景就可以對NPC進行管理,不需要多余的處理,而弊端則在于在刷新的時候是同步刷新的,也就是說一個場景里面的NPC可能會在同一時間內長出來。而對于第二種方法呢,設計起來會稍微麻煩一些,需要一個統一的機制讓NPC登陸到場景,還需要一些比較麻煩的設計,但是這種方案可以實現NPC異步的刷新,是目前網絡游戲普遍采用的方法,下面我們就來著重談談這種方法的實現:
  首先我們要引入一個“靈魂”的概念,即一個NPC在死后,消失的只是他的肉體,他的靈魂仍然在世界中存在著,沒有呼吸,在死亡的附近漂浮,等著到時間投胎,投胎的時候把之前的所有屬性清零,重新在場景上構建其肉體。那么,我們怎么來設計這樣一個結構呢?首先把一個場景里面要出現的NPC制作成圖量表,給每個NPC一個獨一無二的標識符,在載入場景之后,根據圖量表來載入屬于該場景的NPC。在NPC的OnDie() 事件里面不直接把該物件destroy 掉,而是關閉NPC的呼吸,然后打開一個重生的計時器,最后把該物件設置為invisable。這樣的設計,可以實現NPC的異步刷新,在節省服務器資源的同時也讓玩家覺得更加的真實。
(這一章節已經牽扯到一些服務器腳本相關的東西,所以下一章節將談談服務器腳本相關的一些設計)
補充的談談啟發式搜索(heuristic searching)在NPC智能中的應用。
  其主要思路是在廣度優先搜索的同時,將下一層的所有節點經過一個啟發函數進行過濾,一定范圍內縮小搜索范圍。眾所周知的尋路A*算法就是典型的啟發式搜索的應用,其原理是一開始設計一個Judge(point_t* point)函數,來獲得point這個一點的代價,然后每次搜索的時候把下一步可能到達的所有點都經過Judge()函數評價一下,獲取兩到三個代價比較小的點,繼續搜索,那些沒被選上的點就不會在繼續搜索下去了,這樣帶來的后果的是可能求出來的不是最優路徑,這也是為什么A*算法在尋路的時候會走到障礙物前面再繞過去,而不是預先就走斜線來繞過該障礙物。如果要尋出最優化的路徑的話,是不能用A*算法的,而是要用動態規劃的方法,其消耗是遠大于A*的。
  那么,除了在尋路之外,還有哪些地方可以應用到啟發式搜索呢?其實說得大一點,NPC的任何決策都可以用啟發式搜索來做,比如說逃跑吧,如果是一個2D的網絡游戲,有八個方向,NPC選擇哪個方向逃跑呢?就可以設置一個Judge(int direction)來給定每個點的代價,在Judge里面算上該點的敵人的強弱,或者該敵人的敏捷如何等等,最后選擇代價最小的地方逃跑。下面,我們就來談談對于幾種NPC常見的智能的啟發式搜索法的設計:
Target select (選擇目標):
  首先獲得地圖上離該NPC附近的敵人列表。設計Judge() 函數,根據敵人的強弱,敵人的遠近,算出代價。然后選擇代價最小的敵人進行主動攻擊。
Escape(逃跑):
  在呼吸事件里面檢查自己的HP,如果HP低于某個值的時候,或者如果你是遠程兵種,而敵人近身的話,則觸發逃跑函數,在逃跑函數里面也是對周圍的所有的敵人組織成列表,然后設計Judge() 函數,先選擇出對你構成威脅最大的敵人,該Judge() 函數需要判斷敵人的速度,戰斗力強弱,最后得出一個主要敵人,然后針對該主要敵人進行路徑的Judge() 的函數的設計,搜索的范圍只可能是和主要敵人相反的方向,然后再根據該幾個方向的敵人的強弱來計算代價,做出最后的選擇。
Random walk(隨機走路):
  這個我并不推薦用A*算法,因為NPC一旦多起來,那么這個對CPU的消耗是很恐怖的,而且NPC大多不需要長距離的尋路,只需要在附近走走即可,那么,就在附近隨機的給幾個點,然后讓NPC走過去,如果碰到障礙物就停下來,這樣幾乎無任何負擔。
Follow Target(追隨目標):
  這里有兩種方法,一種方法NPC看上去比較愚蠢,一種方法看上去NPC比較聰明,第一種方法就是讓NPC跟著目標的路點走即可,幾乎沒有資源消耗。而后一種則是讓NPC在跟隨的時候,在呼吸事件里面判斷對方的當前位置,然后走直線,碰上障礙物了用A*繞過去,該種設計會消耗一定量的系統資源,所以不推薦NPC大量的追隨目標,如果需要大量的NPC追隨目標的話,還有一個比較簡單的方法:讓NPC和目標同步移動,即讓他們的速度統一,移動的時候走同樣的路點,當然,這種設計只適合NPC所跟隨的目標不是追殺的關系,只是跟隨著玩家走而已了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444972.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444972.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444972.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小談Online-game服務器端設計(4)

在這一章節,我想談談關于服務器端的腳本的相關設計。因為在上一章節里面,談NPC智能相關的時候已經接觸到一些腳本相關的東東了。還是先來談談腳本的作用吧。   在基于編譯的服務器端程序中,是無法在程序的運行過程中構建一些東西的&#xf…

leetcode45 跳躍游戲II 秒殺所有答案

給定一個非負整數數組,你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 你的目標是使用最少的跳躍次數到達數組的最后一個位置。 示例: 輸入: [2,3,1,1,4] 輸出: 2 解釋: 跳到最后一個位置的最小跳躍數是 2。 從下標為 …

MachineLearning(7)-決策樹基礎+sklearn.DecisionTreeClassifier簡單實踐

sklearn.DecisionTreeClassifier決策樹簡單使用1.決策樹算法基礎2.sklearn.DecisionTreeClassifier簡單實踐2.1 決策樹類2.3 決策樹構建2.3.1全數據集擬合,決策樹可視化2.3.2交叉驗證實驗2.3.3超參數搜索2.3.4模型保存與導入2.3.5固定隨機數種子參考資料1.決策樹算法…

游戲服務器體系結構

本文描述了一個我所設計的游戲服務器體系結構,其目的是實現游戲服務器的動態負載平衡,將對象從繁忙的服務器轉移到相對空閑的服務器中.設計并沒有經過具體的測試與驗證,僅僅是將自己目前的一些想法記錄下來.隨著新構思的出現,可能會有所變化. 以下是服務器的邏輯視圖,其中忽略…

游戲服務器架構探討

要描述一項技術或是一個行業,一般都會從其最古老的歷史開始說起,我本也想按著這個套路走,無奈本人乃一八零后小輩,沒有經歷過那些苦澀的卻令人羨慕的單機游戲開發,也沒有響當當的拿的出手的優秀作品,所以也…

leetcode72 編輯距離

給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少操作數 。 你可以對一個單詞進行如下三種操作: 插入一個字符 刪除一個字符 替換一個字符 示例 1: 輸入: word1 "horse", word2 "ros" 輸出: 3 解釋: ho…

即時通訊系統架構

有過幾款IM系統開發經歷,目前有一款還在線上跑著。準備簡單地介紹一下大型商業應用的IM系統的架構。設計這種架構比較重要的一點是低耦合,把整個系統設計成多個相互分離的子系統。我把整個系統分成下面幾個部分:(1)狀態…

leetcode303 區域和檢索

給定一個整數數組 nums,求出數組從索引 i 到 j (i ≤ j) 范圍內元素的總和,包含 i, j 兩點。 示例: 給定 nums [-2, 0, 3, -5, 2, -1],求和函數為 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0,…

算法(24)-股票買賣

股票買賣1.動態規劃框架LeetCode-121 一次買賣LeetCode-122 不限次數LeetCode-309 不限次數冷凍期LeetCode-714 不限次數手續費LeetCode-123 兩次買賣LeetCode-188 k次買賣2.貪心特解LeetCode-121 一次買賣LeetCode-122 不限次數解題思路參考buladong解題,詳細信息可…

網絡游戲的客戶端同步問題 .

有關位置同步的方案實際上已經比較成熟,網上也有比較多的資料可供參考。在《帶寬限制下的視覺實體屬性傳播》一文中,作者也簡單提到了位置同步方案的構造過程,但涉及到細節的地方沒有深入,這里專門針對這一主題做些回顧。 最直接的…

leetcode319 燈泡的開關

初始時有 n 個燈泡關閉。 第 1 輪,你打開所有的燈泡。 第 2 輪,每兩個燈泡你關閉一次。 第 3 輪,每三個燈泡切換一次開關(如果關閉則開啟,如果開啟則關閉)。第 i 輪,每 i 個燈泡切換一次開關。 …

網游服務器端設計思考:心跳設計

網絡游戲服務器的主要作用是模擬整個游戲世界,客戶端用過網絡連接把一些信息數據發給服務器,在操作合法的情況下,更新服務器上該客戶端對應的player實體、所在場景等,并把這些操作及其影響廣播出去。讓別的客戶端能顯示這些操作。…

算法(25)-括號

各種括號1.LeetCode-22 括號生成--各種括號排列組合2.LeetCode-20 有效括號(是否)--堆棧3.LeetCode-32 最長有效括號(長度)--dp4.LeetCode-301刪除無效括號 --多種刪除方式1.LeetCode-22 括號生成–各種括號排列組合 數字 n 代表生成括號的對數,請你設計一個函數&a…

(二十)深入淺出TCPIP之epoll的一些思考

Epoll基本介紹 在linux的網絡編程中,很長的時間都在使用select來做事件觸發。在linux新的內核中,有了一種替換它的機制,就是epoll。相比于 select,epoll最大的好處在于它不會隨著監聽fd數目的增長而降低效率。因為在內核中的select實現中,它是采用輪詢來處理的,輪詢的fd…

leetcode542 01矩陣

給定一個由 0 和 1 組成的矩陣,找出每個元素到最近的 0 的距離。 兩個相鄰元素間的距離為 1 。 示例 1: 輸入: 0 0 0 0 1 0 0 0 0 輸出: 0 0 0 0 1 0 0 0 0 示例 2: 輸入: 0 0 0 0 1 0 1 1 1 輸出: 0 0 0 0 1 0 1 2 1 注意: 給定矩陣的元素個數不超過 10000。…

RPC、RMI與MOM與組播 通信原理 .

遠程過程調用(RPC): 即對遠程站點機上的過程進行調用。當站點機A上的一個進程調用另一個站點機上的過程時,A上的調用進程掛起,B上的被調用過程執行,并將結果返回給調用進程,使調用進程繼續執行【…

網關服務器 .

之前想著要把什么什么給寫一下,每次都太懶了,都是想起了才來寫一下。今天只討論游戲服務器的網關服務器。 1.轉發 轉發客戶端和服務器間的消息,網關將場景、會話、數據、名字、平臺等服務器的數據轉發給客戶端,接收客戶端的數據&a…

算法(26)-最長系列

最長系列1.LeetCode-32 最長有效括號--子串2.LeetCode-300 最長上升子序列--長度3.LeetCode-32 最長回文子串--是什么5.LeetCode-512 最長回文子序列--長度6.LeetCode-1143 最長公共子序列--長度6.LeetCode-128 最長連續序列--長度7.LeetCode-14 最長公共前綴-字符串8.劍指offe…

一個簡單的游戲服務器框架 .

最近一段時間不是很忙,就寫了一個自己的游戲服務器框架雛形,很多地方還不夠完善,但是基本上也算是能夠跑起來了。我先從上層結構說起,一直到實現細節吧,想起什么就寫什么。 第一部分 服務器邏輯 服務器這邊簡單的分為三…

游戲登陸流程 .

當公司有很多游戲的時候,那么公司往往會有一個統一的賬號管理平臺,就就像盛大通行證、網易通行證,戰網平臺,這些平臺統一管理游戲的賬號數據。 打個比方,現在我們玩星辰變,那么玩家登陸游戲的時候…