當前位置: 華文問答 > 遊戲

網絡遊戲是如何同步的?

2015-05-21遊戲

過往專案中也有MMO遊戲,網絡同步這塊自然走的是狀態同步方案。

但因為只負責前端工作,對後端的邏輯只是知其然不知其所以然,所以對自己在狀態同步上的理解不是很滿意。

剛好圈內大佬麒麟子在cocos商店上架了一款「 TGX線上對戰全棧框架 」,前後端使用的都ts語言,對我來講是一個很好的學習後端狀態同步細節的機會。

於是在這裏對TGX框架展開學習,對狀態同步方案做梳理、沈澱,並順帶討論一點程式設計師高效學習進步的方法論。

---職場學習方法論---

進入職場之後,對個人的要求就是能夠快速解決具體範圍的問題,所以相對在校學習,職場學習有它迥異的特點,面臨的挑戰有如下5個——

1、真正能用

學習的知識要能夠服務業務,落實到日常工作

2、突發學習

需求和問題通常是突發的,為了解決問題需要快速掌握所需技能

3、時間碎片

職場中不會預留學習時間,而只會給到解決問題的時間

4、零散雜亂

面向解決問題學習雖然能夠完成工作,但它有一個很大的缺點,就是學到的知識會非常零散,難以提取和復用

5、不停在變

需求、專案、公司、行業都在變,掌握的技能如何做到可遷移,這是一個問題

根據職場學習的特點,我使用的方法論是 功利性學習 + 框架 = 可遷移

即利用「 功利性學習 」快速掌握技能,解決真正能用、突發學習的問題;使用「 框架 」組織知識點,解決時間碎片和零散雜亂的問題,最終實作技能的 可遷移

所以這次對狀態同步的學習,首先我會1> 只學習TGX框架中與狀態同步相關 的部份 2>將學習所得沈澱, 加入我的技能框架 3>最終做到 可遷移 ,有一套自己面向狀態同步的核心演算法和設計方案。

---帶著問題---

在閱讀TGX框架源碼之前,我先回憶自己的研發經驗,並找到一些資料對狀態同步做調研,先對其有個初步的知識框架,然後從源碼找答案來驗證和補充框架。

0、業務背景

1>同場景中有多個實體2>實體之間會產生互動,操作會互相影響

1、一句話套路總結

1>前端,所有實體都是 演員 ,透過接收到的數據進行「 表演

2>後端,需要持有遊戲世界所有實體的數據(狀態),不管數據是從哪來的

3>後端,要做裁判,判定實體操作的合法性和資源的歸屬

2、狀態同步,同步的是什麽?

狀態 」在這裏是一個很抽象且寬泛的概念,可以理解為遊戲世界中每一個可變實體的數據集合,可以透過數據還原實體,在實際開發中同步物體的全量或部份(變化)的數據皆可。

同步 」要做的就是將自己控制實體的數據發送給其他玩家,將其他玩家控制實體的數據發送給自己。

3、前後端的架構設計有哪些?

前端發操作,後端計算狀態並行給所有前端( 完全信任後端 ),狀態完全來自於後端的計算,這是 最理想的情況

套用專案

MMORPG(大型多人線上角色扮演遊戲)

優點

安全

缺點

後端需要實作完整的邏輯,難度較大

------------

前端發狀態,後端轉發狀態給所有前端( 完全信任前端 ),狀態完全來自於前端,套用好場景很狹窄

套用專案

線上教育1(老師)V多(學生),且學生間操作沒有聯系。學生每次操作時將自己端所有實體的狀態打包成快照發給伺服器用於轉發。

優點

後端只用寫轉發,邏輯非常簡單

缺點

不安全,分分鐘外掛,但線上教育不存在外掛問題,算是特殊場景特殊設計。

------------

前端選主機,主機接收操作並計算狀態,後端將主機的狀態轉發給所有前端( 完全信任作為主機的前端

套用專案

一款開房對戰遊戲,伺服器不想寫邏輯,又得有一定的反外掛能力

優點

後端只用寫轉發,邏輯非常簡單

缺點

網絡繞了一圈,速度更慢,完全不適用對及時反饋要求較高的遊戲所有人可能被主機的網絡速度卡住安全性仍然比較低,主機開掛沒得解

想法

後端不想寫邏輯,用訊框同步最好了這種特別不好,後端實作邏輯為最優設計。如果實在不行,幹脆拋棄伺服器,用 p2p 通訊得了,還能省掉一層伺服器轉發的時間。

綜上,我認為將狀態的計算放在後端是最優解,一是為了玩家登入時「還原現場」,二是玩家有資源競爭時需要後端做裁判,三是為了安全,反外掛;

4、如何反外掛?

這裏只列舉一下,展開講的話篇幅太大,需要另外開文,況且當前我也不精通。

玩法設計上防外掛

比如當前多數卡牌遊戲,抽卡結果是後端給的,戰鬥過程是假的,外掛無從下手。

或者瞬移、透視等效果在玩法設計上考慮好,使得作弊本身不會帶來什麽收益。

加密

本地程式碼、網絡通訊做好加密,並隨著日常更新經常變一變,增加破解成本

數值放在後端

關鍵狀態的計算放在後端,比如傷害數值等

玩家舉報與外掛檢測

交給玩家,當發現異常時玩家舉報,後台透過記錄的數據校驗是否真的使用了外掛

法律手段

找到外掛制作、售賣方,抓之。但一般小公司沒精力、成本做這件事。

--TGX框架學習--

進入正題!

做架構設計/復雜系統設計的最有效方式就是畫 UML( 統一建模語言),從源碼中反推架構設計和邏輯的執行流程也是如此。

這裏選取TGX框架中的坦克大戰專案來學習,聚焦於它核心戰鬥的設計,用類圖和時序圖來表達。

類圖——

上面是核心戰鬥的類圖,省略了非核心的類與非核心的介面。

被標註為綠色的類與坦克自身相關。

Tank

管理坦克自身數據,包括playerid、狀態、動畫、攻擊、被擊介面等。

TankMovement2D

將對移動的管理抽象為一個獨立的類,坦克的移動以及移動速度等都由它管理。

NameHP

負責管理坦克的血條與名稱的顯示

TankBullet

負責子彈的位移和碰撞

被標註為灰色的類負責相機跟隨

FollowTarget

相機跟隨,只有一個lateUpdate()介面,職責就是每幀將相機座標設定為坦克的座標。

這個非常優雅,在沒有2d攝影機的時代,可是透過相對於角色移動反向位移地圖來實作地圖捲動的,現在方便多了。

被標註為黃色的類負責控制坦克,包括移動、射擊等

TankController

所以它同時和Tank與TankMovement2D關聯

最後被標註為藍色的是核心,狀態同步最重要的邏輯在這

TankGameMgr

負責監聽網絡訊息,然後透過監聽者模式拋給業務層處理

TankGameScene

在玩家可見的螢幕上做同步,如其他玩家的移動,攻擊、受擊等。

時序圖——

前面已經透過類圖了解了坦克大戰的靜態設計,知道了有哪些類以及它們的職責。

接下來更重要啦——透過時序圖搞懂類之間的動態關系,狀態同步的核心也在這個動態關系裏面。

關鍵的點有進入戰場,新玩家加入、玩家離開、坦克移動,坦克攻擊,坦克受擊,下面一一分析

約定:綠色表示是伺服器模組,藍色表示是客戶端程式碼

進入戰場——

一句話,後端將全部實體的數據發給前端,然後前端透過數據還原現場。

當玩家加入戰場時,會先觸發後端的onUserEnter介面,它會把所有實體的數據發給前端

其中this._gameData的數據結構如下,可以看出,的確是全部實體的集合

然後前端觸發onNet_game_data_sync_push()回呼,拿到所有玩家的數據,足以還原整個戰場

新玩家加入——

一句話,後端創造新玩家的狀態數據,發送給前端,前端透過數據創造實體。

後端創造和發送數據到前端

前端收到並建立實體

玩家離開——

一句話,後端刪掉對應實體的數據,然後通知前端刪掉對應實體。

後端程式碼

前端程式碼

坦克移動——

一句話,每幀都同步實體座標、角度到伺服器,伺服器轉發給所有玩家

TankController的lateUpdate介面中判斷當前實體在移動(speed大於0)時則每訊框同步自己的座標、角度數據給伺服器

後端收到數據存起來,並轉發給所有前端

其他前端收到數據,同步實體位置、朝向

坦克攻擊——

一句話,前端實體攻擊,將數據發給後端,後端再轉發給所有前端

當實體攻擊時前端先行建立一個子彈,然後把子彈的起點等數據發給後端

後端原樣轉發給所有前端

前端判斷如果不是自己,則播放攻擊動畫,建立一個子彈

坦克受擊——

一句話,前端做碰撞檢測,發給後端,後端算好被攻擊方氣血,發給前端做表現。

TankBullet在lateUpdate中檢測自己是否與敵方坦克碰撞,如果碰撞則發給後端說擊中目標。

後端收到訊息則計算傷害數值

--我從TGX源碼得到的驗證--

一句話,TGX框架已經提供了優秀的狀態同步的核心演算法和架構設計樣版,在具體專案的研發時只需要根據業務,把狀態的計算適當地放在後端即可。

套路——

1、前端,的確全是演員。除自己外的所有實體(坦克,即Tank類)都是根據後端發來的狀態出場(建立)、下場(銷毀)和表演(更新狀態)。

在TGX框架中,自己的狀態更新是不等待網絡回包的,這是狀態同步最佳化的經典做法,即「預測與回滾」,是為了更好的遊戲體驗。

2、後端,的確持有遊戲世界所有實體的數據(狀態),不管數據是從哪來的。

新加入的實體由後端生成數據;座標、朝向、攻擊、碰撞判定的數據由前端生成;氣血和得分的數據由後端生成。

3>後端,要做裁判,判定實體操作的合法性和資源的歸屬

體現在實體氣血和得分的計算上,是後端做裁判的。

架構設計——

比較符合這張圖的設計,區別在於有些狀態是由前端計算得來的。

但為了遊戲體驗和減輕伺服器計算壓力,將部份狀態的計算交給前端處理也是合理的。

反外掛——

盡量往後端放就好了,只涉及業務邏輯開發,架構一點都不用改。

後端計算座標,前端就沒辦法做瞬移掛;後端計算傷害數值,就沒辦法做秒殺掛;後端計算氣血就沒辦法做鎖血掛。

--如果是我,我會怎麽做?--

學習源碼,我的另外一個心得是——抽演算法,寫架構。

即核心演算法可以用源碼的,但是對演算法的封裝要自己寫,寫一個符合自己設計習慣的架構。

所以我的架構設計是

實體作為演員,由Entity類管理,它有兩個子類別,即坦克與子彈。

我習慣用狀態機管理邏輯,所以為每個實體整合了兩個狀態機,分別管理邏輯和動畫,做到邏輯和表現分離。

由SelfEntityControll作為控制輸入,原則上它把操作發給伺服器,再由EntityMgr接收來自伺服器的回包,最後驅動Entity去「表演」。

一些設計tips

1>狀態的計算盡量往後端放

2>自己也盡量等待後端回包後再行動,「移動」這種為了最佳化體驗可以前端先預測,其他操作則要仔細斟酌。

鳴謝

有TGX感覺我也能全棧啦~

閱讀TGX源碼,和自己的經驗做比較,是一種和大佬之間的高效對話。

心動了麽?點選下方連結跳轉購買(沒廣告費,是真的好)

TGX線上對戰全棧框架 】 https:// store.cocos.com/app/det ail/5504