一般認(rèn)為幀同步的錄像會更容易實現(xiàn),因為對于每個客戶端,戰(zhàn)斗由用戶操作命令序列驅(qū)動愿棋,只需要記錄命令序列均牢,在播放錄像時再重播這個序列即可。對于狀態(tài)同步甘邀,其實錄像的原理和幀同步比較類似垮庐,因為驅(qū)動服務(wù)器執(zhí)行戰(zhàn)斗邏輯的也是用戶的命令序列,我們同理可以記錄每個服務(wù)器幀用戶的輸入突硝,在播放錄像時回放用戶的輸入解恰,即可復(fù)現(xiàn)戰(zhàn)斗過程浙于。
復(fù)現(xiàn)戰(zhàn)斗過程的本質(zhì)是要做到完全一致的命令序列,在完全一致的時間軸上羞酗,在完全相同的環(huán)境(相同的環(huán)境目前主要是隨機(jī)性一致)下執(zhí)行,即可得到完全一致的結(jié)果胸竞。要注意幾個比較核心的問題:
要保證錄像和戰(zhàn)斗是完全一致的命令序列参萄,需要按順序記錄處理的命令。這個雖然看起來比較簡單校赤,但是實際上卻比較容易踩坑筒溃,要注意接受到用戶命令的時間點和真正處理用戶命令的時間點之間的差異。
狀態(tài)同步戰(zhàn)斗服務(wù)器執(zhí)行命令序列最好的做法是定幀處理命令浑测,這樣就可以在播放的錄像的時候?qū)⒚钚蛄袆澐值讲煌膸?zhí)行歪玲,能夠比較容易實現(xiàn)一致的時間軸怎顾。反之漱贱,如果命令是實時處理的,在復(fù)現(xiàn)時對時間精度要求極高幅狮,不易實現(xiàn)復(fù)現(xiàn)。
所有計時都由唯一的delta_time驅(qū)動擎值,如果服務(wù)器幀是10幀逐抑,delta_time取const 100ms,這里要注意的是delta_time不能獲取真實的幀與幀之間的時間差进每,因為delta_time會有很低的概率出現(xiàn)波動命斧,不是100ms。這一點也是用來保證時間軸一致的贤徒。
隨機(jī)性可控汇四,要保證錄像和實際戰(zhàn)斗的隨機(jī)序列的一致,一般使用同樣的隨機(jī)種子即可通孽,如果使用了第三方的庫也要注意保證隨機(jī)一致的問題。這個是保障戰(zhàn)斗是在相同的隨機(jī)環(huán)境下執(zhí)行挨厚。
驅(qū)動狀態(tài)同步計算的不僅僅是用戶輸入糠惫。對于我們的游戲的某個版本,為了提高子彈命中和扣血的匹配巢价,所有子彈的扣血由客戶端命中后向服務(wù)器請求觸發(fā),獲取扣血結(jié)果進(jìn)行顯示城菊。這個子彈命中的命令是實時處理的碉克,這點與我們第一條要求相悖,我們要做到完全同樣的時間點執(zhí)行子彈命中是比較麻煩的一件事漏麦,但是好在我們有第二點原則,所有時間都是由delta_time驅(qū)動更耻,我們只需要在每幀的用戶輸入序列執(zhí)行前執(zhí)行與上一幀之間的子彈命中命令捏膨,即可完成復(fù)現(xiàn)。這里有一個假設(shè)是目胡,服務(wù)器每幀的執(zhí)行期間不會有子彈命中命令到達(dá)诚隙,這個我們通過加鎖來實現(xiàn)。在游戲后面的版本中,子彈的命中改為由服務(wù)器驅(qū)動效五。
保證所有命令的執(zhí)行不會有并發(fā)。
容器的訪問順序問題脉执。不要使用對象直接做key戒劫,因為對象的內(nèi)存地址是不穩(wěn)定的,這樣訪問順序可能會存在不確定性巫橄。