原文鏈接:Fast-Paced Multiplayer (Part III): Entity Interpolation
在系列的第1篇文章中,我們介紹了1種權(quán)威服務(wù)器的思想還有他在避免玩家做弊方面的優(yōu)勢。但是直接使用這類技術(shù)會引發(fā)可玩性和響應(yīng)性方面的問題。在第2篇文章中,我們提出了1種客戶端預(yù)測的方法來處理。
到現(xiàn)在為止我們提出了1套解決方案,能夠讓玩家在多人游戲中得到單人游戲般流暢的體驗,即便是在接入權(quán)威服務(wù)器并且有1定網(wǎng)絡(luò)延遲的情況下。
在這篇文章中,我們將會處應(yīng)當(dāng)有別的玩家連入相同的服務(wù)器的問題。
在前面的文章中,服務(wù)器的行動非常的簡單 - 讀取客戶真?zhèn)€輸入,更新游戲狀態(tài),然后將結(jié)果返回給客戶端。當(dāng)超過1個客戶端連接的時候,服務(wù)器的主循環(huán)邏輯就有點不1樣了。
在這類情況下,1些客戶端可能同時快速地發(fā)送輸入(比如按方向鍵,移動鼠標(biāo)或單擊),每次收到客戶真?zhèn)€要求就更新游戲,然后再把救過進(jìn)行廣播, 這樣會消耗大量的CPU和帶寬。
1種好的方式是將玩家的輸入壓到隊列中去而不馬上進(jìn)行處理,服務(wù)器在1定的頻率上進(jìn)行相對低頻率的更新,比方說沒秒10次。每次更新之間的時長稱為時間步長,在這里是100ms。在每次的更新迭代中,所有的未處理的輸入都今次那個處理(可能會比時間步長更小1些,來讓物理更可預(yù)測1些)然后新的游戲狀態(tài)就廣播給所有的客戶端。
總的來講,游戲世界的更新應(yīng)當(dāng)在1種可預(yù)測的頻率,獨立于玩家的輸入。
從玩家的角度看,這類方式還是像之前的方法1樣順滑 - 客戶真?zhèn)€預(yù)測獨立于更新的延遲,所以對可預(yù)測的狀態(tài)更新是沒有問題的。但是,由于游戲狀態(tài)以1種低頻率進(jìn)行廣播,這將致使游戲看上去非常卡頓,多是100ms更新1次位置。
在客戶端2中看到的客戶端1的情況
根據(jù)你開發(fā)的游戲類型,可能有很多方法來處理,通常你的游戲?qū)嶓w越可預(yù)測,越好處理。
假定你在做1個賽車游戲。1輛快速開著的車是非常可預(yù)測的 - 假定他的速度是100m/s,那末1s以后,它應(yīng)當(dāng)大致在離起始點100m遠(yuǎn)的位置。
為何是“大致”?由于在這1秒中以內(nèi),車可能加速1點,也可能減速1點,向右1點或向右1點 - 這里說的是1點點。由于車的機動性,車確當(dāng)前位置總是依賴于它之前的位置,速度和時間。而不是玩家的輸入,換句話說,1輛快速運行的車沒法瞬間180度掉頭。
1個每秒更新10次的服務(wù)怎樣來處理呢?客戶端收到每輛車的速度和朝向以后,在接下來的100ms內(nèi),它不會遭到任何新的信息,但是客戶端還是要進(jìn)行更新啊。最簡單的方法就是假定車在這100ms內(nèi),朝向和加速度都是常量,然后讓這輛車?yán)^續(xù)運行,100ms以后,收到更新包以后,再對車的速度進(jìn)行糾正。
糾正可能很大也可能很小,依賴于很多因素,如果玩家保持直線運行并且不改變車的速度,那末預(yù)測的結(jié)果和正式的位置是完全1致的。另外一方面,如果玩家撞到甚么東西,預(yù)測的位置就完全錯了。
有1點要提1下,航位推的算法可以利用在慢速的情況下 - 比如戰(zhàn)艦。其實這類算法最初就用在海上導(dǎo)航。
有許多情況航位推是沒法處理的 - 對玩家的方向和速度可以瞬間改變的都不行,比如3D射擊,玩家常常快速跑動,停下,快速轉(zhuǎn)向等,在這類情況下,航位推算法就非常無力了。由于位置和速度和前面的數(shù)據(jù)無關(guān)。
你可以選擇在接到服務(wù)器的要求的時候直接更新玩家的位置,而客戶端看到的就是網(wǎng)上其他的玩家每100ms跳1下,感覺會非常奇怪。
你現(xiàn)在具有的是每100ms由服務(wù)器傳送過來的權(quán)威數(shù)據(jù),現(xiàn)在要做的是如何在這100ms內(nèi)讓網(wǎng)絡(luò)角色看起來非常自然,解決問題的關(guān)鍵就是將網(wǎng)絡(luò)玩家顯示在過去的某個時刻。
假定你在t=1000收到位置信息,你已在t=900收到了1次位置信息,所以你知道玩家在t=900和t=1000的位置,所以在t=1000到t=1100之間,你只要顯示玩家t=900到t=1000的位置。這類方法,你所顯示的都是玩家的真實數(shù)據(jù),只是有100ms的延遲。
客戶端2渲染的是客戶端1的角色過去的位置,利用插值來更新位置
用來插值的t=900和t=1000的數(shù)據(jù)依賴于游戲。插值通常都可以處理得很好。如果不是這類方法,你可能需要服務(wù)器發(fā)送更加詳細(xì)的移動信息了 - 比如更多的位置采樣點,或每10ms發(fā)送1次(你沒必要發(fā)10倍的數(shù)據(jù) - 由于你發(fā)的微小的位移數(shù)據(jù),在這類情況下數(shù)據(jù)的格式可以很好的優(yōu)化1下)。
當(dāng)使用這類技術(shù)的時候,每個玩家都和游戲世界有1點點不同步,由于每一個玩家看到自己的世界是當(dāng)前的,但是其他的玩家都是過去的。但即便是快速的游戲,這100ms的延遲都不是那末明顯。
有1種情況除外 - 當(dāng)你需要時間和空間的準(zhǔn)確性的時候,比如1個玩家射擊另外一個玩家的時候,由于其他的玩家都是存在于過去的某個時候,你的瞄準(zhǔn)實際上是有100ms的延遲的 - 也就是說,你設(shè)計的目標(biāo)是100ms的某個目標(biāo)! 這個問題我們下1篇會進(jìn)行討論。
在權(quán)威服務(wù)器的環(huán)境中,有著不肯定的服務(wù)器更新和網(wǎng)絡(luò)延遲,在這類情況下你還要給玩家平滑的移動。在第2篇中,我們展現(xiàn)了1種客戶端預(yù)測和服務(wù)器調(diào)和的技術(shù),來實現(xiàn)實時的角色控制,這樣的方案讓玩家能夠得到即時的反饋,移除致命的延遲。
其他玩家的同步還是1個問題,但是,在這篇文章中,我們提出了兩種解決方案。
第1種是航位推技術(shù),這類摹擬需要entity的位置能夠通過前1個時候的位置,速度,加速度來推算出來,當(dāng)不滿足這類情況的時候,航位推就沒用了。
第2種是插值技術(shù),不預(yù)測將來的位置,只是使用服務(wù)器傳來的數(shù)據(jù),這類就會造成顯示的entity總是過去的某個時刻。最后的結(jié)果就是玩家的角色總是當(dāng)前時刻,而其他看到的entity都是過去的某個時刻,這類情況可以產(chǎn)生1種難以置信的無縫體驗。
但是,當(dāng)游戲需要高速離散的準(zhǔn)確性的時候,比如射擊或移動物體,美景就幻滅了:你看其他玩家的位置和服務(wù)器的位置不1致,別的玩家看你的位置也不是正確的,這樣爆頭就不可能產(chǎn)生了!很多游戲都有爆頭這1說,我們將在下面的文章中來討論這個問題。