幀同步之從零開始

一直想寫一個多人在線遊戲,也一直在研究相關的技術。從目前瞭解到的信息來看,網絡遊戲的同步方案大部分狀況下是:幀同步或狀態同步。下面就介紹一下,我對幀同步的一些瞭解。git

基本概念


什麼是幀同步?簡化的流程以下圖。 github

幀同步

紅色箭頭:客戶端向服務端發送玩家的操做指令。(A-A: 玩家A按下A鍵)服務器

藍色箭頭:服務器每隔一段時間T,向全部客戶端發送當前收集到的客戶端指令。網絡

幀同步原理就是這麼簡單:同步玩家的全部操做而非狀態(HP、攻擊力、位置)。當客戶端收到服務端的消息時,進行遊戲狀態更新,即圖中藍色箭頭位置。因此理想狀態下,全部客戶端的更新都是同步的。由於繪製時間點是統一的,指令也是一致的,那麼就是完美的同步了。socket

網絡延遲


那麼問題來了,若是出現網絡延遲怎麼辦?性能

幀同步

實際渲染時,玩家A將比玩家B更早收到消息,意味着玩家A的設備裏角色已經開始動了而玩家B的設備裏遊戲角色仍是沒有反應,即不一樣步。若是不做處理,隨着網絡波動,將會致使遊戲進行到必定程度後,玩家A和玩家B是兩個不一樣的遊戲畫面。優化

優化方案


其實,影響不一樣步的因素有不少,網絡延時多是最直觀的。下面我列舉一下,別人和我本身實踐中用到的優化方案。ui

  1. 避免浮點數運算(不一樣設備下會出現精度不一致的狀況,效應疊加就會「差之毫釐謬以千里」)
  2. 減少每次發包的數據量(網絡遊戲是頻繁通訊的:10-20次/s)
  3. 邏輯幀與渲染幀(不一樣設備性能不一,不能將全部遊戲的狀態更新都放在渲染循環裏)
  4. 不一樣步的插值優化(網絡問題的致使的不一樣步,須要優化處理,手段不一)

實踐


爲了研究幀同步,寫了一個TANK.IO。項目後續會更新,如今這個實現並不完美。socket.io

主要的優化操做:spa

  • 避免浮點數運算

    對小數進行有效位數限定。

    export function toFixed(i, precision=3) {
      return +i.toFixed(precision)
    }
    複製代碼
  • 利用msgpack壓縮數據,socket.io有對應插件

    const
      parser = require('socket.io-msgpack-parser'),
      io = require('socket.io')(3000, {parser})
    複製代碼

PS: 不一樣步的優化感受不是很好,就不發出來了。能夠本地運行一下代碼,在局域網下運行,遊戲總體還過得去。

參考資料


從《王者榮耀》來聊聊遊戲的幀同步

相關文章
相關標籤/搜索