幀鎖定算法解決游戲同步
早期 RTS,XBOX360 LIVE游戲常用同步策略,如何才能像單機(jī)游戲一樣編寫網(wǎng)游??
算法概念
該算法普遍要求網(wǎng)速RTT要在100ms以內(nèi),一般人數(shù)不超過8人,在這樣的情況下,可以像單機(jī)游戲一樣編寫網(wǎng)絡(luò)游戲。所有客戶端任意時(shí)刻邏輯都是統(tǒng)一的,缺點(diǎn)是一個(gè)人卡機(jī),所有人等待。
1.客戶端定時(shí)(比如每五幀)上傳控制信息。
2.服務(wù)器收到所有控制信息后廣播給所有客戶。
3.客戶端用服務(wù)器發(fā)來的更新消息中的控制信息進(jìn)行游戲。
4.如果客戶端進(jìn)行到下一個(gè)關(guān)鍵幀(5幀后)時(shí)沒有收到服務(wù)器的更新消息則等待。
5.如果客戶端進(jìn)行到下一個(gè)關(guān)鍵幀時(shí)已經(jīng)接收到了服務(wù)器的更新消息,則將上面的數(shù)據(jù)用于游戲,并采集當(dāng)前鼠標(biāo)鍵盤輸入發(fā)送給服務(wù)器,同時(shí)繼續(xù)進(jìn)行下去。
6.服務(wù)端采集到所有數(shù)據(jù)后再次發(fā)送下一個(gè)關(guān)鍵幀更新消息。
這個(gè)等待關(guān)鍵幀更新數(shù)據(jù)的過程稱為“幀鎖定”
應(yīng)用案例:大部分RTS游戲,街霸II(xbox360),Callus模擬器。
算法流程
客戶端邏輯:
1. 判斷當(dāng)前幀F(xiàn)是否關(guān)鍵幀K1:如果不是跳轉(zhuǎn)(7)。
2. 如果是關(guān)鍵幀,則察看有沒有K1的UPDATE數(shù)據(jù),如果沒有的話重復(fù)2等待。
3. 采集當(dāng)前K1的輸入作為CTRL數(shù)據(jù)與K1編號(hào)一起發(fā)送給服務(wù)器
4. 從UPDATE K1中得到下一個(gè)關(guān)鍵幀的號(hào)碼K2以及到下一個(gè)關(guān)鍵幀之間的輸入數(shù)據(jù)I。
5. 從這個(gè)關(guān)鍵幀到下 一個(gè)關(guān)鍵幀K2之間的虛擬輸入都用I。
6. 令K1 = K2。
7. 執(zhí)行該幀邏輯
8. 跳轉(zhuǎn)(1)
服務(wù)端邏輯:
1. 收集所有客戶端本關(guān)鍵幀K1的CTRL數(shù)據(jù)(Ctrl-K)等待知道收集完成所有的CTRL-K。
2. 根據(jù)所有CTRL-K,計(jì)算下一個(gè)關(guān)鍵幀K2的Update,計(jì)算再下一個(gè)關(guān)鍵幀的編號(hào)K3。
3. 將Update發(fā)送給所有客戶端
4. 令K1=K2
5. 跳轉(zhuǎn)(1)

服務(wù)器根據(jù)所有客戶端的最大RTT,平滑計(jì)算下一個(gè)關(guān)鍵幀的編號(hào),讓延遲根據(jù)網(wǎng)絡(luò)情況自動(dòng)調(diào)整。
算法演示
我根據(jù)該算法將街機(jī)模擬器修改出了一個(gè)可用于多人對(duì)戰(zhàn)的版本,早期有一個(gè)叫做kaillera的東西,可以幫助模擬器實(shí)現(xiàn)多人聯(lián)機(jī),但是并沒有作幀鎖定,只是簡(jiǎn)單將鍵盤消息進(jìn)行收集廣播而已,后來Capcom在PSP和360上都出過街霸的聯(lián)網(wǎng)版本,但是聯(lián)網(wǎng)效果不理想。這個(gè)算法其實(shí)局域網(wǎng)有細(xì)就經(jīng)常使用了,只是近年來公網(wǎng)速度提高,很容易找到RTT<50ms的服務(wù)器,因此根據(jù)上述算法,在平均RTT=100ms(操作靈敏度1/10秒),情況下,保證自動(dòng)計(jì)算關(guān)鍵幀適應(yīng)各種網(wǎng)絡(luò)條件后,就能夠像編寫單機(jī)游戲一樣開發(fā)網(wǎng)游,而不需狀態(tài)上作復(fù)雜的位置/狀態(tài)同步。

從上圖的演示中可以看到,兩個(gè)模擬器進(jìn)程都在運(yùn)行1941這個(gè)游戲,兩邊客戶端使用了該算法,將邏輯統(tǒng)一在一個(gè)整體中。

最后這張圖是運(yùn)行KOF99的效果圖,兩邊完美同步。