動作類遊戲如何在高延遲下實現同步?不同的客戶端網路情況,如何實現延遲補償?十年前開始關注該問題,轉眼十年已過,看到大家還在問這類問題,舊文一篇,略作補充(關於遊戲同步相關問題還可以見我寫於2023年的另外兩篇文章,幀鎖定演算法 和 網遊同步法則):
影子跟隨演算法由普通dr(dead reckoning)演算法發展而來,我將其稱為「影子跟隨」意再表示演算法同步策略的主要思想:
1. 螢幕上現實的實體(entity)只是不停的追逐它的「影子」(shadow)。
2. 伺服器向各客戶端傳送各個影子的狀態改變(座標,方向,速度,時間)。
3. 各個客戶端收到以後按照當前重新插值修正影子狀態。
4. 影子狀態是跳變的,但實體追趕影子是連續的,故整個過程是平滑的。
圖1 演算法演示
前面的1號終端控制紅色飛船p1向左飛,並把自己的狀態時時告訴伺服器
後面的2號終端上接收到飛船p1的影子s1的狀態(向左移動),並讓p1的實體追趕s1
網路效能指標一:頻寬,限制了實時遊戲的人數容量
網路效能指標二:延時,決定了實時遊戲的最低反應時間
使用該演算法可以容易的開發出一款馬里奧賽車,或者counter strike,詳細說明見後:
演算法比較:
1. 幀間同步:不同客戶端每幀顯示相同的內容,鍵盤/時鐘資料傳到伺服器,伺服器確認後所有終端做出響應,多用於區域網遊戲,比如紅警(需要等待客戶端),街霸ii的網路版(360),網速要求高,複雜度低。參考以及 lockstep和timewrap演算法,以及我2023年舊文 幀鎖定演算法。
2. 插值同步:不同客戶端顯示不同步,但是狀態同步,常見的dead reckoning(或叫導航插值),效果好,但複雜度高。常見於競速類遊戲和 fps遊戲。
演算法定義:
2. 玩家:每個玩家控制自己的實體,並在每貞將狀態改變告知伺服器。
3. 狀態:狀態資料 = 實體id + 座標 + 方向 + 速度 + 時間(貞)。
4. 插值:收到新狀態包後將根據其運動方向與時間,根據現有時間計算當前的新狀態。
5. 跟隨:實體不停的追蹤自己的影子,追上後與影子保持狀態同步。
相位滯後:可選引數,實體與影子保持一定距離同步,相當於保持一定車距,這樣在控制者突然停止的時候,不容易因為網路延遲跑過了又被拉回來。
慣性移動:可選引數,開始移動或者停止或者改變方向都有加速度,這樣就不需相位滯後了。
每次伺服器向各個客戶端同步時間的時候,由於延遲,所有客戶端的時間都是慢於伺服器的,這沒有關係,只要大家在一定誤差範圍內以相同的速度增加,就完全沒有問題。
圖2 idc網路響應
在公網平均130ms的latency下,是不存在「完全的」的同步情況。如何通過消除/隱藏延時,將使用者帶入快速的互動式實時遊戲中,體驗完美的互動娛樂呢?
讓所有的使用者螢幕上面表現出完全不同的表象是完全沒有問題的;
把這些完全不同表象完全柔和在乙個統一的邏輯中也是完全沒有問題的。
需要根據具體情況,分清楚哪些我們可以努力,哪些我們不值得努力,弄明白實時遊戲中同步問題關鍵之所在,巧妙的化解與規避遊戲,最終在適合普遍使用者網路環境中(200ms),實現實時快速互動遊戲。
案例解析:counter strike
實現cs的話,首先我們需要給人物移動加上慣性,比如靜止狀態突然開始移動,那麼需要0.5-1秒的加速過程,而移動中突然停止也需要0.5-1秒的減速過程,這樣就實現了無差別同步,不需要相位滯後來避免拉扯影響使用者感。
同時開槍射擊採用客戶端判斷,也就是說如果我看見你在牆前面,開槍射中,那麼我向伺服器傳送「我擊中你了」,這時有可能真實的你在牆後,那麼表現出來的就是我看見我打中你了(減不減血由服務段判斷),而你沒有看見我,覺得我穿牆打中你了。
圖3 cs的同步邏輯
關鍵狀態進行快取,不然如果別人向前連續跳五次,每次取得狀態都取到最高點的話,別人客戶端上的影子和跟隨的實體會奇怪的持續的飛在天上,所以需要將起跳和落地這兩個關鍵狀態快取,實體追趕時只有追上的第乙個狀態(一號影子)才能追逐第二個狀態(二號影子)。
由此可以在完全時間同步的情況下平滑的跑動、跳躍,開槍射擊採用客戶端判斷後手感得到提高,唯一需要擔心的就是外掛程式,外掛程式多是實時遊戲的代價,只能通過cheating death等工具防止了。
案例解析:馬里奧賽車
用該演算法實現馬里奧賽車是很簡單的,影子和實體都使用慣性,由於賽車慣性很大,不容易有突變的狀態更新,所以效果會比fps遊戲更好。
玩家碰到道具後,馬上在螢幕上隱藏該道具的顯示並通知伺服器,由伺服器決斷道具屬誰,由於剛碰到道具就隱藏所以不會有碰到道具卻在一段時間內無法取得延遲現象。
遊戲道具系統實現也很容易,比如那個將當前第一名炸毀的道具,它的描述是:原角色+物件角色+約定發生時間。既然知道物件是誰,什麼時間發生,那就更本不需要怎麼同步了,所有客戶端和伺服器在該時間讓炸彈**就得了,這種手法類似即時戰略遊戲。
遊戲還有一類道具是可以發射的烏龜殼,這個東西屬於有彈道的發射物,類似quake裡面的某些**,需要作一些同步處理,基本特性是伺服器判斷起決定作用,客戶端同步判斷,如果客戶端與伺服器都判斷集中,那就集中;如果客戶端判斷集中而伺服器判斷沒有集中,那會看到該角色似乎被打了一下,但很快又恢復了速度向前衝。
由於賽車本身就具備慣性比較大的特點,因此同步效果是比較好的,可以在更大的延遲情況下表現得和fps差不多(比如300ms效果相當於fps的200ms)。
非可靠包:
該「影子跟隨演算法」支援非可靠傳輸協議,如果使用非可靠傳輸,那麼我們按照特定頻率(如每秒10次)定時傳送狀態更新,因為協議中每個更新包出了位置外還有速度、方向和時間,甚至還能加速加速度,因此我們丟乙個包沒有關係,可以根據後來的包重新計算插值。只有關鍵狀態更新時才需要可靠傳輸,這就避免了tcp中丟包時rto指數增長造成的延遲了。
負面情況:
該演算法缺點就是無法向「幀間同步」演算法那樣,每次傳送按鍵給伺服器,伺服器處理後再反饋結果,在區域網中(平均延遲<5ms),這樣的效果相當於單機遊戲一樣即時,遊戲性也能很複雜。然而在internet中(平均延遲130ms,設計基準200ms,每秒最多傳送10個資料報)該演算法卻不能像單機遊戲那樣有複雜的場景互動,有類似格鬥遊戲的即時的動作判定。
許多策劃在設計實時動作遊戲時很多設計我們都難以實現,這樣因為策劃不容易明白哪些我們能做,哪些我們不能做。即便程式設計師精通同步理論,策劃也經常碰壁。
當多數設計被程式設計師回覆「無法實現」後,策劃只有採取一種消極設計(砍掉很多有意思的互動元素),於是網路遊戲的表現力到今天還是差單機遊戲一大截。
這些問題也並不能因為「影子跟隨演算法」的提出而得到改進,大於100ms的判定時間,都很難做到即時。
最後,該演算法編碼複雜度比其他同步策略高,因為伺服器需要計算乙份影子資料,各個客戶端需要計算乙份影子資料,還需要計算實體追趕,而這三種計算都需要在同樣的時鐘下保持一致,這就增加了編碼與除錯的複雜度。
總結話題:
internet特點是「高頻寬,高延遲」,可以說從本質上internet就不是為了遊戲而設計的。故此internet絕對意義的同步是不存在的。「影子跟隨演算法」的核心思想有幾個:時鐘同步,客戶端先行,平滑追趕。通過這三個特性,我們能夠在近似時間同步的情況下,模擬各種物體的移動過程,而使用該演算法的前提是設計者需要根據各個遊戲的特性研究不同的優化技巧,策略因遊戲而變。
比如傳送狀態更新包時,不需要每次都傳送,而可以只傳送改變的狀態。什麼時候我們覺得改變了?就是當客戶端實體與自己的影子之間的誤差大於某特定數值時我們才傳送更新包,這樣雖然玩家在原地做左右搖擺的小幅度移動,只要沒有超出範圍,都不需要傳送新的狀態更新,其他玩家機器上看起來,它是站著不動的。
比如當發現某客戶端5秒鐘沒有相應了,那麼就將該人物的影子凍結住,永遠不要為了等待某個資料而不讓遊戲進行下去。
本演算法需要客戶端與伺服器維護相同的時鐘,當每5分鐘同步的時候,直接根據伺服器的時鐘替換當前時鐘就行了,不需要重新計算所有影子的位置,因為後續的狀態資料將會馬上重新整理這些狀態。更不需要將測量到的ping值考慮進去,該演算法與ping具體值無關。
當發現策劃案子不可行時,尋找近似替代方案,比如減少「一次性的」「決定性的」事件發生,比如延長飛彈在空中飛行的時間,比如將敵人加入hp分多次打死,而不是以及斃命,等等,都是大家可以發揮想象的地方。
相關例子:
文章相關demo如果有需要的話,可向我索要。
文獻參考:
林偉(2007),幀鎖定演算法
林偉(2005),網遊同步法則
棋牌遊戲如何解決現有問題?
一,體現獨特性 遊戲有創新 目前國內大大小小的棋牌遊戲開發公司大概有2000家,由於棋牌遊戲大體格局十分相似,所以大部分公司旗下的產品不管從版本還是功能方面都沒有明顯的差異。棋牌遊戲同質化,是阻礙其在市場競爭中停滯不前的因素。所以我們可以看到,市場上有很多產品的優勢是非常不明顯的,玩家可能玩過即忘,...
如何解決併發
雖然從巨集觀上,處理器是並行處理多項任務,但本質上乙個處理器在某個時間點只能處理乙個任務,屬於序列執行。在單處理器的情況下,併發問題源於多道程式設計系統的乙個基本特性 程序的相對執行速度不可 它取決於其他程序的活動 作業系統處理中斷的方式以及作業系統的排程策略。在分布式環境下,併發產生的可能性就更大...
如何解決藍屏問題
第一步 公升級筆記本bios 一般說來筆記本在出廠的時候很可能設計上存在某些的瑕疵,而廠商通常會採用公升級bios的方法來解決這些bug。如果我們在使用筆記本腦的過程中遇到了藍屏的情況,那麼我們可以採取公升級bios的辦法來解決藍屏的故障。第二步 正確安裝硬體驅動 在重新整理了bios以後,部分筆記...