Unity幀同步的實(shí)現(xiàn)方法

幀同步

游戲同步主要方向是 狀態(tài)同步和幀同步。

狀態(tài)同步

狀態(tài)同步簡單來說就是有一個(gè)權(quán)威服務(wù)器運(yùn)行著一個(gè)沒有圖形界面的客戶端,然后服務(wù)器收集所有人的操作數(shù)據(jù) 計(jì)算后再把所有人的關(guān)鍵數(shù)據(jù)廣播給所有人,玩家的客戶端只是服務(wù)器的一個(gè)展示。
缺點(diǎn)是有些情況下同步數(shù)據(jù)量會很大 因?yàn)橛?jì)算全在服務(wù)器所以可能壓力會比較大。


幀同步

幀同步中的每一個(gè)客戶端都是要計(jì)算所有數(shù)據(jù),服務(wù)器只需要轉(zhuǎn)發(fā)彼此的操作即可。
幀同步的同步過程:
1.收集所有人的輸入,廣播給所有人。
2.客戶端接收到所有人的輸入,客戶端本地開始根據(jù)輸入計(jì)算得到游戲結(jié)果。
優(yōu)點(diǎn) 服務(wù)器壓力小,同步的數(shù)據(jù)量也很小相對應(yīng)的可以有更低的延遲和帶寬占用,可以直接沒有服務(wù)器。天生支持錄像。
缺點(diǎn) 反作弊難度較大,所有數(shù)據(jù)都在客戶端本地。


在Unity中實(shí)現(xiàn)幀同步的注意事項(xiàng)

如果要做幀同步 就必須保證所有客戶端再執(zhí)行相同操作的情況下的結(jié)果必須百分百一樣,這樣我們就不可以使用Unity自帶的物理引擎。(親測 會不同步)
因?yàn)椴煌琧pu和操作系統(tǒng)可能float的精度也不同 所以也要避免使用float。(雖然說float有固定標(biāo)準(zhǔn)的,按理來說現(xiàn)在不同平臺已經(jīng)都一樣了,但是謹(jǐn)慎起見我還是沒用float)
幀同步的核心邏輯也不可以寫在Unity腳本的生命周期里 例如Update


幀同步的大致實(shí)現(xiàn)原理

首先要區(qū)分 邏輯幀和渲染幀。
我們同步的是邏輯幀,所有位移和傷害判定什么的也都是在邏輯幀中,渲染幀中做平滑處理。
Unity中的幀就可以當(dāng)作是渲染幀。 每次Update就是一個(gè)渲染幀,每次FixedUpdate就可以當(dāng)作是邏輯幀。 渲染幀是沒有固定間隔的 性能高刷的就快間隔就短。而邏輯幀是必須固定間隔的。

我兩臺手機(jī)要創(chuàng)建房間進(jìn)行游戲。

  1. 首先手機(jī)A點(diǎn)擊創(chuàng)建房間,手機(jī)A啟動服務(wù)器,不停的把自己的IP和端口號 以及房間信息(人數(shù),地圖,模式。。。等) UDP局域網(wǎng)廣播給一個(gè)固定端口。 其他手機(jī)客戶端固定監(jiān)聽這個(gè)端口,收到房間信息的廣播就在UI界面中顯示。

  2. 廣播房間之后等待其他客戶端鏈接進(jìn)來,房間滿員之后 所有人開始加載地圖。

  3. 服務(wù)器收到所有人加載完畢消息之后,服務(wù)器開始循環(huán)記時(shí) 服務(wù)器來驅(qū)動邏輯幀。比如 1秒20邏輯幀 就是0.05秒驅(qū)動一幀,把收到的客戶端輸入廣播給所有人。(服務(wù)器的主要職責(zé)就是定時(shí)轉(zhuǎn)發(fā)輸入)。


    image.png
  4. 客戶端在服務(wù)器開始計(jì)時(shí)之后 在每一個(gè)Unity渲染幀中都把自己的輸入發(fā)送到服務(wù)器,服務(wù)器每一個(gè)邏輯幀按照最后一次收到的輸入廣播給所有人。
    客戶端發(fā)送Input數(shù)據(jù)

image.png

服務(wù)器接收Input數(shù)據(jù)


image.png

服務(wù)器廣播Input消息


image.png
  1. 客戶端自己本身不進(jìn)行邏輯幀計(jì)時(shí) 收到一個(gè)服務(wù)器發(fā)來的邏輯幀,先給所有角色設(shè)置input 然后再客戶端本地就按照固定的時(shí)間間隔更新物理 驅(qū)動邏輯幀(比如1秒20邏輯幀 就是每次更新物理0.05秒)
image.png
image.png
  1. 然后物理更新的時(shí)候 自己用事件管理器廣播一下PhysicsUpdate事件 其他地方監(jiān)聽物理更新事件。寫核心邏輯的地方 用物理更新的Update代替Unity的Update 就可以像寫單機(jī)游戲一樣做幀同步游戲了。

上面的例子中 服務(wù)器的那臺機(jī)器 如果渲染幀卡了一秒 而邏輯幀1秒20幀 ,那么就直接一個(gè)渲染幀中調(diào)用20次邏輯幀 追趕上進(jìn)度。 如果服務(wù)器卡住了 所有人也都會同步暫停。 如果你有需要 也可以做主機(jī)遷移 隨時(shí)接替原來的主機(jī) 防止房主掉線 大家一起掉線。


最終效果

image.png

image.png

image.png

預(yù)測回滾

無論幀同步還是狀態(tài)同步理論上來說都要做預(yù)測回滾,狀態(tài)同步做這個(gè)還好做一點(diǎn)。
預(yù)測回滾基本就是按照上一次的操作客戶端自動多模擬一幀或者幾幀 來抵消網(wǎng)絡(luò)延遲的感覺,但是如果預(yù)測結(jié)果和之后真實(shí)發(fā)生的結(jié)果不符的時(shí)候 就需要回滾客戶端到正常的結(jié)果上 然后再次預(yù)測。 (如果一個(gè)人在游戲里 反復(fù)左右移動 比如CS里對槍時(shí) 瘋狂ADADADADAD左右移動 這種情況下 如果有客戶端有預(yù)測回滾 就會瘋狂的預(yù)測錯(cuò)誤而回滾 客戶端也會增加額外的計(jì)算壓力)
預(yù)測回滾因?yàn)槲易约鹤龅男Ч懿缓?大概如下圖一樣,所以我就不講具體怎么做了。
(英雄聯(lián)盟的預(yù)測回滾做的也不咋樣,設(shè)置里面有個(gè)預(yù)測選項(xiàng)默認(rèn)是關(guān)閉的 手動勾選打開之后 就算網(wǎng)絡(luò)正常效果也跟下圖一樣。)

6D32E5F7CE9A74018528F9E5BD2717B7.gif

預(yù)測回滾的方案很多 并不是只有一種,像《戰(zhàn)地3》的預(yù)測回滾就特別魔性 你如果擊中敵人了 但是因?yàn)檠舆t導(dǎo)致服務(wù)器判定沒擊中,但是你客戶端已經(jīng)提示擊中了 再對其他人影響不大的情況下 它會讓其他所有玩家和服務(wù)器陪著他一塊回滾 讓子彈打中那個(gè)人。。。。 (難道這就是我快速躲進(jìn)掩體里之后還被打死的原因?)。


幀同步的作弊檢查

游戲過程中檢測

玩家每一邏輯幀執(zhí)行結(jié)束之后 把所有角色的關(guān)鍵數(shù)據(jù)加密為MD5 上傳服務(wù)器,服務(wù)器進(jìn)行比對。如果是所有人上傳上來的MD5都一樣 說明所有人的游戲結(jié)果都是同步的,如果有人修改了血量那么就會造成游戲不同步 自己的MD5和其他人的不一樣,服務(wù)器可以強(qiáng)行糾正它 或者 踢掉它。

事后檢測

游戲結(jié)束之后上傳整場比賽左右的操作數(shù)據(jù),服務(wù)器開一個(gè)客戶端 一瞬間跑完所有操作所有幀 看最終的結(jié)果與客戶端上報(bào)上來結(jié)果是否一致,如果不一致肯定有人作弊了。

不容易檢測的作弊

像透視 自瞄這種 本質(zhì)上沒有改變游戲數(shù)據(jù)的作弊 就不太容易檢測。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容