离散事件模拟在游戏中的应用
離散事件模擬(discrete event simulation),這個東西可能在游戲領域用得并不是很多,它是模擬仿真領域的一個仿真模型,用來模擬在時間軸上一系列離散事件后,整個系統(tǒng)的變化情況,這么說,可能還是有點抽象,給大家舉一個使用離散事件模擬的一個經(jīng)典的例子,如何計算銀行柜臺排隊的平均等待時間。
先簡要描述一下這個場景,假設一個銀行有兩個柜臺,每個柜臺都可以辦理業(yè)務,每隔3分鐘都會有一位客戶進來辦理業(yè)務,如果有空的柜臺,那他就直接辦理,如果沒有,就排隊,每個人辦理的業(yè)務時間都不同,可能是1~10分鐘的任意一個時間,整個銀行的營業(yè)時間是8小時,那請計算,在8小時所接待的所有客戶中,客戶的平均等待時間是多少?
這個問題,如果靠數(shù)學方法來計算,并不是很容易,那換一個思路就是,我可不可以把整個這個8小時的過程模擬一遍,把每一個客戶的等待時間記錄下來,然后求平均,這樣就可以得到這個平均等待時間了。當然,真的把模擬的過程跑8個小時,太沒有效率了,所以這個時候,就可以用離散事件模擬的方法,對這個問題去快速的進行仿真。
離散事件模擬有幾個基本的概念,我們可以結(jié)合上面的這個例子來一個個看:
時鐘(Clock):整個模擬是按照時間去前進的,也就是有一個虛擬的時間去跟蹤當前的時間,在這里,這個時鐘就是從銀行開門,一直到銀行關門,總長8小時
結(jié)束條件(Ending Condition):模擬結(jié)束所要滿足的條件,因為不可能無限模擬下去,在這里,結(jié)束條件,就是時間到了8小時
事件(Event):在時間軸上需要處理的事件,每個事件都有發(fā)生的時間,并且事件是按照時間的先后排列在時間軸上的,在這里,有幾個事件,客戶到達銀行,客戶結(jié)束辦理業(yè)務。
整個模擬過程是怎么樣的呢?簡單的一句話,就是不斷的從時間軸上處理一個個的事件,直至滿足結(jié)束條件或者所有的事件都處理完畢。由于在相鄰的兩個事件與事件之間,是沒有任何事情發(fā)生的,所以時鐘是可以從當前的事件觸發(fā)的時間直接跳到下一個事件觸發(fā)的時間,這也就是“離散事件”的含義,因為這些“事件”在整個時間軸上是離散分布的,從時間的角度來看,整個模擬過程是“跳躍”前進的。
?
新的事件可以通過在處理老的事件的時候來不斷的產(chǎn)生,并且添加到時間軸上,繼續(xù)用上面的例子,我們把“客戶n在時間t到達銀行”這個事件記為E(Arrive,n,t),把“客戶n在柜臺m用了t分鐘結(jié)束了業(yè)務辦理”這個事件記為E(Finish,n,m,t),第一個事件,就是E(Arrive,Tom,0),也就是銀行一開門,來了一個用戶叫Tom,這樣在時間軸上,現(xiàn)在是這樣的。
?
這樣我們初始化就好了,現(xiàn)在銀行開門,我們開始進行8小時的模擬
我們先處理第一個事件E(Arrive,Tom,0),當前時鐘設為事件的時間,第0分鐘,這個事件處理的時候,因為現(xiàn)在柜臺是空的,所以Tom選擇了1號柜臺,并且需要用了8分鐘辦理業(yè)務,那我們就在時間軸上再添加一個時間E(Finish,Tom,1,8),并且,我們還需要往時間軸再添加下一個“客戶到達事件”,假設3分鐘后會來一個客戶叫Jerry,這樣時間軸上又加了一個事件E(Arrive,Jerry,3),這個事件會加在E(Finish,Tom,1,8)前面,因為它會先發(fā)生。
?
然后我們開始處理第二個事件,因為事件是按照時間軸排序的,所以我們一定能拿到一個最近要發(fā)生的事件,現(xiàn)在的例子里,這個事件是E(Arrive,Jerry,3),又來了一個客戶Jerry,當前時鐘設為事件的時間,第3分鐘,處理的過程和上面一樣,QQ賣號不過Jerry選擇2號柜臺,我們會壓兩個事件,E(Finish,Jerry,2,3+6),E(Arrive,Mary,3+3),值得注意的是,事件發(fā)生的時刻,我用了3+6這樣的形式,也就是表示,當前時鐘是第3分鐘,這個事件需要在當前時鐘的往后的6分鐘發(fā)生。
按照我們的時間軸,第三個事件,是E(Arrive,Mary,3+3),當前時鐘設為事件的時間,第6分鐘,這個時候,我們不能直接為Mary添加E(Finish)事件,因為沒有空的柜臺,所以Mary只能選擇排隊,但下一個E(Arrive)事件還是需要添加。
第四個事件,總算輪到很早就添加的E(Finish,Tom,1,8),所以添加的早,不一定執(zhí)行的早,因為這個模擬是按照時間來推進的,當前時鐘到了第8分鐘,這個時候Tom的業(yè)務辦完了,在處理E(Finish)事件的時候,我們就要去看,是不是有人在排隊,如果有人在排隊,那就要為排在第一個的用戶,添加E(Finish)事件,現(xiàn)在這個人是Mary,那我們就添加E(Finish,Mary,1,8+6),在1號柜臺,預計花6分鐘的時間結(jié)束。
?
這樣基本上所有可能的情況我們都簡單描述了,剩下的,就是讓這個模擬過程一直跑,整個過程,就是不斷的有事件被處理,然后又不斷的有事件產(chǎn)生,到最后8小時的時候,銀行關門,模擬結(jié)束。基于這個模擬過程,平均等待時間就很容易算了,客戶來的時間記t1(也就是處理E(Arrive)的時間點),客戶開始辦業(yè)務的時間記t2(也就是添加E(Finish)事件的時間點),然后t2-t1,就是單個客戶的等待時間,然后把所有等待時間求和,再除以所有的客戶數(shù),就是平均等待時間了。
這個東西說起來好累,其實實現(xiàn)起來并不復雜,在我維護的那個TsiU的庫中,已經(jīng)實現(xiàn)了一個離散事件模擬的工具庫,也就100多行代碼,非常簡單。在項目中,我用這個方法,做過一個工具,用來模擬在特定的同時在線數(shù)量的情況下玩家匹配游戲的平均等待時間,這樣可以幫助運營人員去確定需要導入多少的用戶量,來盡可能的減少匹配的等待。離散事件模擬,對于這種情景可以說是一個非常好用的利器,概念簡單,實現(xiàn)快捷。不過在實際的游戲?qū)用?#xff0c;它可不可以發(fā)揮作用呢?或者說,有沒有什么游戲情景可以用這個方法去架構(gòu)呢?答案是,可以有!
說了一大圈,總算到了這次分享的正題了。離散事件模擬是可以用在某些特定的游戲情境中,比如有一些游戲是戰(zhàn)報類的,也就是說你點擊了戰(zhàn)斗之后,后臺系統(tǒng)就已經(jīng)把整個戰(zhàn)斗的過程算好了,然后客戶端就是把整個戰(zhàn)斗結(jié)果來回放一遍,這種類型的戰(zhàn)斗就很適合用離散事件模擬來架構(gòu)(不知道類似的游戲有沒有采用這樣的方法),假設我們采用類似于早期最終幻想的ATB戰(zhàn)斗系統(tǒng),也就是每個參加角色都有個自己的時間條,誰先長滿了就誰先行動,速度高的角色時間條長得快一點,速度低的角色時間條就長得慢一點。
?
要模擬這樣一場戰(zhàn)斗就可以用離散事件模擬的結(jié)構(gòu),假設我們先簡化為只能進行攻擊的行動,我們就會有一個事件就是攻擊,E(Attack,t),在戰(zhàn)斗的一開始,我們把速度最快的那個人的E(Attack,t)添加到時間軸上(有點類似于上面銀行的例子里,排在最前面等處理業(yè)務的那個人),然后開始進行模擬,在處理E(Attack,t)時,需要進行以下幾步
?
- 處理傷害
- 添加下一個行動的人的E(Attack,t)
- 把自己加入行動的隊列
一直進行模擬,直到己方勝出或者團滅。再復雜一點,如果再攻擊中改變了時間條的增長速度,那么就需要對行動隊列進行調(diào)整,也就是重新按照速度排序。這樣當這場戰(zhàn)斗模擬完畢的時候,就可以把所有的模擬過程的數(shù)據(jù)發(fā)送給客戶端,由客戶端進行戰(zhàn)斗表現(xiàn)。
不過,在這種模擬過程中,游戲內(nèi)是不能進行操作的,也就說,整個戰(zhàn)斗是自動進行的,那如果需要支持操作,那個應該怎么處理呢?對于使用離散模擬的游戲來說,是沒有辦法做到“實時操作,實時生效”的,不過可以做到“實時操作,延時生效”,這在某些游戲中是很常見的,比如像類似于足球經(jīng)理類的游戲,在你看比賽模擬的時候,你可以進行戰(zhàn)術改變,換人等操作,這種操作對于玩家來說并不需要很高的實時性,只要在一段時間后能生效就可以了,再比如上面說的ATB的戰(zhàn)斗系統(tǒng),假設玩家可以在觀看戰(zhàn)斗的時候,能夠使用一些全局魔法,這個時候,就可以用一些“施法時間”的概念來告訴玩家,你的施法是需要時間的,來掩蓋無法實時生效的問題,但是又保證了服務器快速的模擬計算,節(jié)省服務器資源。
用離散事件模擬做“實時操作,延時生效”的關鍵,就是采用“分段模擬”,也就是不是一下子模擬整個過程,而是模擬一段時間,等待一段時間,再模擬一段時間,這樣,如果玩家的操作發(fā)生在上一個時間段,那我就可以在下一個時間段模擬的時候,加入玩家操作的影響。
?
采用“分段模擬”的時候,和客戶端通信會采用一段一段數(shù)據(jù)發(fā)送的方式,服務器先模擬一段時間的數(shù)據(jù),比如模擬10秒鐘邏輯,然后推送給客戶端,之后等待一段時間,這段時間不能超過每段的模擬時間,一般可以等待50%~80%的模擬時間,比如等待5~8秒鐘,如果等待超過10秒鐘(甚至接近10秒鐘),就會導致客戶端那邊播放完了,新的數(shù)據(jù)還沒到,從而客戶端的表現(xiàn)產(chǎn)生卡頓的情況,后續(xù)就一直循環(huán)這個過程,直到整個模擬結(jié)束。
離散事件模擬在游戲中雖然不是很常用,不過也是可以作為一個知識點,儲備在那里,當遇到適合的場合,就可以作為選擇之一加以應用。具體的例子我就不寫了,大家有興趣可以用TsiU里的那個庫,自己做一個模擬銀行平均等待時間的程序,來體會一下,有任何問題,和指教,歡迎討論。
總結(jié)
以上是生活随笔為你收集整理的离散事件模拟在游戏中的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技术人员是如何分析游戏环境的? 《影之诗
- 下一篇: 游戏的数值系统的实现和演化