最近看了比較多的網路同步問題因為我只做過回合制,沒做過arpg,所以稍微去看看大致是怎麼實現的。基本上可以歸為兩個問題:玩家位置同步和戰鬥指令同步。玩家位置同步的情況要比戰鬥指令同步的情況簡單,不過正因為如此,你為了更好的同步,就會採取複雜的同步策略。另外,這兩種同步其實是息息相關的,戰鬥肯定會涉及到位置判斷。所以我打算一起思考這兩個問題。
首先我們要知道在arpg遊戲中,是需要對時協議的,就是說客戶端和服務端的時間戳要基本保持一致。至於這個對時的頻率和策略,可以有各種優化的版本,我們只考慮最簡單的情況,就是每隔一段時間同步時間戳。一般可能是5hz或者10hz,當然戰鬥時候肯定會高些,平時可以降低些。
為啥需要乙個時間戳呢?因為不論是位置同步,還是防止玩家使用加速器,包括客戶端作弊等,在有時間戳的情況下會簡化很多。
首先利用對時協議可以讓客戶端和服務端得知網路延遲的大概時間。雖然是大概,但也是比較準確的。
為了更好的闡述問題,我們假定玩家a,網路延遲為1s,玩家b,網路延遲為2s。這是非常大的延遲,因為如果是100ms左右的延遲,其實不用採取任何技術你都能跑得比較爽。
玩家a本來位於座標5,下達了向座標10移動的指令,玩家速度為1,服務端接收到指令的時候,玩家理論上其實已經到座標6了,這裡我們是無法讓玩家a等待伺服器響應再移動的,因為沒人受得了我移動一下都要卡1s。服務端知道網路延遲為1s,所以可以輕易估算出位置為6,同時向b通知a的位置, b獲得了a的座標,其實a應該已經到8了,當然b也知道網路延遲,所以也能估算出a的位置應該是8。一切看上去都似乎還可以,但不難發現一些問題。首先,網路延遲是不穩定的,忽高忽低,根據時間戳去計算,是需要檢測其合法性。比如延遲高達10s,你估算的結果都快讓玩家瞬移了,我們可以判定10s的延遲肯定是不合理,甚至可以丟棄這個包。假定2s一下的延遲才會進入估算,而2s以上的,恐怕還是當做2s來處理。那玩家如果作弊呢?發各種各樣奇怪的位置過來,這也是需要檢測的,服務端肯定有玩家原來的位置,通過與玩家新位置的比較,看看兩者的時間差有沒有可能做這樣的移動,如果沒可能,說明有作弊嫌疑,多次發現,就直接踢下線處理。這樣似乎解決了這個問題。但再思考,玩家a下達這個指令後,b將a同步到8,突然a的第二條指令來了,a跑到5.5之後,其實往回跑了,同理,服務端接收到資訊,發現a的位置是5.5,這和本來**的位置6相差0.5,說明自己的**產生了誤差,我們依然採取相信客戶端的做法,因為假如你強行同步a位置為6,那麼玩家a會產生往回跑的奇怪體驗。這時服務端通過估算a在4.5,當然a可能突然停下來,這個問題我們不考慮,因為只需要增加乙個停下來的指令或者判斷目標位置就可以解決。服務端這時候通知b,a到4.5了,b收到資訊,估算出a應該在2.5,發現問題所在了吧,a本來應該在8的怎麼突然跑到2.5了?當然由於中間只經過了0.5秒,所以a在b看來還沒到8,只是在向8跑的路上,大概是7。如果我們沒有任何估算,那麼情況會變成a在6,服務端認為是5,同時告訴b a在5,延遲了1, 如果a跑到5.5回頭,那麼a其實在4.5,服務端認為是5,b收到也是5,這樣看起來似乎也沒那麼糟糕。那麼問題的癥結來了,如果不估算,那麼毫無疑問,服務端獲得的位置是客戶端延遲前的資料,客戶端得知其他玩家的位置則是兩邊延遲的疊加。這絕不是乙個好的策略。那麼估算的風險我們也看到了,可能會誤打誤撞反而是誤差變大。我們發現誤差變大的原因是玩家突然變嚮往回跑,導致經過一堆延遲後的速度相反,反而是誤差增大。但也許這些都不是問題,這裡我拷貝雲風大大的一段話:
一種,收到的資訊是屬於其它玩家的。我們從最新得到的狀態資訊,**一段時間之後(比如一秒後的狀態),用一條直線運動去修正。即,設想一秒後這個玩家在**,然後反推回現在應該用什麼速度運動可以在一秒後到達那個地方。
另一種,收到的資訊是屬於自己的,即伺服器認可的自己的狀態(並廣播給別人了)。這個偏差是由於伺服器的**補償造成的。為了保持使用者的操作手感,對於不太極端的偏差,我們全部不修正,而是依然傳送客戶端自己操作的位置狀態給伺服器。伺服器那邊玩家是處於一種離散的運動狀態的。而其他人見到你會再做**補償;如果和伺服器相差過於劇烈,則直接跳轉到伺服器認可的新位置。
這裡幾乎全部相信客戶端的行為,以獲取最好的操作手感。防止客戶端作弊是另外乙個話題,也不是不能解決的,但目前不要碰了。
客戶端到底以怎樣的頻率傳送那些位置資訊給伺服器呢?
策略應該是這樣的:
每次傳送完乙個完整的位置資訊後,**伺服器看待這個位置資訊包一秒後的位置大約在**。每次變化做乙個累積,一秒內都但不用立刻傳送。但每次小的狀態改變都和假設的**位置做一些比較,如果位置偏差比較大,就可以提前傳送。否則一直累計到一秒再傳送。
這個一秒的週期可以根據實際測試情況來調整。可能一秒太短,也可能過長了。
每次收到伺服器傳送過來的新的玩家位置資訊時,都在裡面會找到乙個時間戳,表識的包發出的伺服器時間。客戶端可以驗算之前的網路延遲是否正確。如果網路延遲穩定在乙個固定值,說明沒有問題。但如果延遲值為負數,則說明之前的對時流程中網路不穩定(可能是因為上下行時間偏差比較大造成的,也可能是當時伺服器負載很大,造成了較大的內部延遲),造成本地時間和伺服器時間的時差計算錯誤。這個時候重新發起對時流程就好了。
以上就是雲風部落格中內容,我們可以看到對於b玩家而言,a玩家其實已經不再誤差範圍內,應該直接將它變成2.5或者4.5,這麼來看由於剛才我們分析b大概在7左右,如果從7變成4.5似乎還是可以接受的。畢竟本來我們就是從5變成了8.一切也沒那麼糟,當然如果你要把它變成2.5,那麼只能使用瞬移了,不然玩家總是以一種比常人快的速度運動了。所以,我個人更喜歡保守估計,不要說太滿,寧願延遲一些位置,也不要過頭了。
那麼我們只能老實接受這個延遲帶來的坑爹現象了嘛?還是有些小技巧的。比如攻擊前搖,你攻擊的時候,先要抖一下,這個抖可能沒有實際作用,但確實的提供了短暫的時間等待服務端返回結果。這當然不算啥技術,但是我們不得不正視乙個事實,網路不好肯定體驗就會變差,而且打不過網路好的玩家。比如pvp,無延時的玩家,幾乎是發出乙個指令就打到你了,你一點辦法都沒有。老實的等待被打吧。當你攻擊別人時,你覺得打中了,但到了伺服器那邊發現人家老早走遠了。所以如果是pve,還是能對網路不好的玩家做些補償,畢竟能打中就當做打中好了。
網路遊戲同步問題
介紹 作為乙個程式,你想過網路多人對戰遊戲是怎麼做出來的嗎?從外行的角度來看多人對戰遊戲是很神奇的 2個或者更多的玩家在同乙個時間經歷了相似的遊戲經歷,感覺他們就像在同乙個虛擬世界中遊戲一樣。但是作為程式設計師我們卻知道事實並不是他們想象的那樣的,他們看到的絕大多數其實都是假象。他們所認為玩家間同時...
網路遊戲同步問題
介紹 作為乙個程式,你想過網路多人對戰遊戲是怎麼做出來的嗎?從外行的角度來看多人對戰遊戲是很神奇的 2個或者更多的玩家在同乙個時間經歷了相似的遊戲經歷,感覺他們就像在同乙個虛擬世界中遊戲一樣。但是作為程式設計師我們卻知道事實並不是他們想象的那樣的,他們看到的絕大多數其實都是假象。他們所認為玩家間同時...
再談網路遊戲同步
呵呵,一年前的這個時候發過一系列討論網路遊戲同步的帖子。一年後的今天,再重新討論討論這個問題。不知道大家是否碰到過這種情況,當某個玩家發出乙個火球,這個火球有自己的運動 軌跡,那麼如何來判斷火球是否打中了人呢?大部分情況,當策劃提出這個要求的時 候,一般會被程式否認,原因是 太麻煩了,呵呵。複雜點的...