https://mp.weixin.qq.com/s/6YF0-_tRr3VQUh1vlh6j6g
1 游戲同步中的主次
開發(fā)多人游戲為了保證讓每個人都有好的游戲體驗,防止作弊總是需要去考慮的。
除此之外,在開發(fā)多人游戲時我們還需要考慮如何“欺騙”玩家的眼睛,讓他們認為他們在同一個世界中。
為了達到這種看上去近似的效果,我們需要確認哪些狀態(tài)是需要同步的,只要同步了這些狀態(tài),這個游戲世界就看上去一樣了。而哪些狀態(tài)是無需同步的,并沒有特別大的影響。
在我們的游戲中,玩家的各種屬性、在世界中的坐標、游戲世界中的敵人各種屬性、道具獲取以及各種觸發(fā)器的觸發(fā)等等都有可能會對游戲的表現(xiàn)產(chǎn)生影響,因此需要考慮同步;但是像例如海底的水泡粒子效果、道具獲取后的碎裂效果,甚至是背景音樂則不會對游戲的表現(xiàn)產(chǎn)生特別的影響,因此并沒有必要去同步這些內(nèi)容。
2 同步輸入or同步狀態(tài)
最基本的游戲網(wǎng)絡同步模型大概可以分為以下4種:
前兩種模型的相同點都在于有一臺機器負責整個游戲世界的模擬,最大的區(qū)別在于這臺負責整個游戲世界模擬的機器是誰。
通常,開發(fā)商或發(fā)行商管理的計算機作為服務器,這也往往需要更多的計算機和運維人員?;谶@種同步模型,客戶端的玩家按下一個按鍵,客戶端并不會真正的執(zhí)行影響游戲狀態(tài)的操作。操作只會被發(fā)往服務器,并在服務器執(zhí)行它,之后服務器將執(zhí)行完這個操作之后的結(jié)果(通常是游戲世界的狀態(tài)變化)返回給客戶端。
搭建服務器雖然能提高游戲體驗,但是確實代價高昂。
最理想的還是通過玩家自己建立host。突然想到,這個結(jié)構(gòu)很像區(qū)塊鏈。查了下確實有在運用區(qū)塊鏈在手游界的。
由于網(wǎng)絡延遲,因此服務器和客戶端并非時刻保持一致的,為了使游戲玩家的狀態(tài)變化自然(主要是指玩家的位置、角度等狀態(tài)),常用一種基于插值的同步算法(影子跟隨算法)
1. 服務器間隔固定的時間向客戶端同步狀態(tài)數(shù)據(jù)
2. 客戶端收到數(shù)據(jù)之后進行同步,一般的屬性數(shù)據(jù)例如血量等等直接根據(jù)服務器的值來同步。而諸如位置等信息在客戶端則保存為ServerPosition或者稱為影子,而客戶端的位置則不斷向ServerPosition靠攏。
3. 位置同步的過程為了更加平滑,要使用插值,步進距為玩家的移動速度。因此,雖然ServerPosition是跳變的,但是在客戶端的表現(xiàn)上卻是連續(xù)平滑的。
當然,將所有的邏輯放到服務器并經(jīng)過服務器的模擬之后再將結(jié)果返回給客戶端的過程會帶來一些滯后感,當玩家對操作的敏感度要求較高時,這顯然不是一個很好的解決方案。因此,客戶端的輸入預測和服務端的延遲補償開始得到應用。通過在客戶端側(cè)的輸入預測,可以讓玩家的輸入得到立刻的反饋。而延時補償則保證了結(jié)果的正確性。這個過程可以基本概括為以下幾個階段:
1. 當玩家按下按鈕時,客戶端立刻執(zhí)行相應的操作例如開始播放某個動作或是開始移動。與此同時,客戶端還會向服務器發(fā)送一條包含了時間戳的消息。
2. 服務器經(jīng)過一段延遲后收到了客戶端發(fā)來的按鈕被按下的消息,于是服務器會回滾到按鈕被按下的時刻,在這個時刻執(zhí)行按鈕對應操作,之后再重新模擬到當前時刻。
3. 之后服務器將當前的狀態(tài)同步給客戶端。
4. 客戶端收到服務器同步過來的數(shù)據(jù),此時由于網(wǎng)絡延遲的緣故,客戶端收到服務器的消息時也已經(jīng)過去一段時間。所以客戶端同樣需要回滾到服務器發(fā)出消息的時刻,并根據(jù)服務器發(fā)送的狀態(tài)來修正自己的狀態(tài)。
雖然這樣做能夠更好的保證玩家的手感,但是我們發(fā)現(xiàn)無論是客戶端還是服務器,一旦收到消息包之后都需要回滾。而這種回滾機制相對來說較為復雜,并且也不容易在已有的游戲中加入這種機制。
(后兩種)Peer to Peer點對點同步模型是一種很經(jīng)典的網(wǎng)絡游戲網(wǎng)絡同步模型。帶有幀同步模型的Peer to Peer在很多RTS游戲中得到了大量應用
它將對游戲世界的模擬分配給了所有玩家,因而每個玩家的客戶端都在模擬著自己的游戲世界。這樣做的一大好處在于玩家的輸入總是立刻響應的,我按下一個按鈕,按鈕造成的結(jié)果便發(fā)生了,同時我需要做的是將我的操作發(fā)送給和我相連的客戶端,讓他們也去根據(jù)我發(fā)送的操作模擬游戲世界。但是這樣做的一大弊端在于不能保證客戶端看到的游戲畫面是一樣的。
因此,游戲行業(yè)大多會采用幀同步模型來保證同步的可靠性。很多早期的RTS游戲都采用了幀同步來作為網(wǎng)絡同步的方案。
RTS游戲中常常伴隨著數(shù)十上百甚至上千個邏輯實體單位,如果采用狀態(tài)同步的話數(shù)據(jù)量相對要大很多。但是如果只同步玩家的操作呢?如果每個客戶端在相同的情況下開始游戲,并且運行完全相同的步驟,那么客戶端就可以不通過接收狀態(tài)同步信息就能保證游戲的同步了。
這也是這種模型的一大優(yōu)勢,我們除了發(fā)送玩家的操作之外幾乎不需要再發(fā)送任何數(shù)據(jù)。這種同步輸入的方式可以說非常適合RTS游戲,因為它們有那么多的單位,同步所有單位的狀態(tài)是不容易的。
因此,采用這種模型就可以把游戲的過程分為一個一個的回合。游戲的每一步都需要通過網(wǎng)絡來收集所有玩家的操作輸入,然后再往下執(zhí)行。當然,一提到“回合”這個詞,大家想到往往是所謂的回合制游戲,但事實上只要回合的頻率足夠快,仍然是可以做出即時游戲的感覺。
大菠蘿就是把等待時間減為0了。
當然,由于沒有同步游戲的狀態(tài),而是同步玩家在游戲內(nèi)的輸入操作,因此實現(xiàn)完全同步還是有一些事情需要注意的。因為一旦一個小小的不同步發(fā)生,就會產(chǎn)生蝴蝶效應,從而引起很明顯的不同步。一個典型的例子便是我以前在開發(fā)一個戰(zhàn)斗回放系統(tǒng)時,發(fā)現(xiàn)由于一個士兵在尋路的時候稍微走到有點不一樣的地方,就導致了一場戰(zhàn)斗的結(jié)果大不相同。
雖然我們目前的項目并沒有采用幀同步的方案,但是還是想和大家分享一點教訓。
例如不要使用浮點型數(shù)據(jù),這是由于舍入會造成誤差,所以建議各位使用整形數(shù)據(jù)。
同樣,另一個又被重視又被忽略的是隨機數(shù)的問題。
大家都知道幀同步要保證隨機數(shù)也完全一致。因此,大家都會去同步隨機數(shù)生成器的種子和它們的使用方式。但是一個潛在的可能性是某一方的非游戲邏輯對象使用了隨機數(shù)生成器,從而造成不同步。例如某一方的移動設備性能更好,也因此屏幕上有一些額外粒子特效,這些粒子特效是有可能會使用隨機數(shù)發(fā)生器的,如果這些游戲邏輯之外的對象使用了隨機數(shù)發(fā)生器就會造成不同步的發(fā)生。