碼農-27:[從零開始的Unity網路同步] 3.遊戲中網路同步的解決方案?

zhuanlan.zhihu.com
圖標

在上一篇文章中,總結得出確定性網路同步的必要性,那麼接下來就考慮如何在Unity中實現確定性了.

1.服務端與客戶端相同頻率模擬(Simulate)

在Unity中,有三個更新方法Update, LateUpdate,FixedUpdate.

UpdateLateUpdate屬於渲染幀,它們每幀間隔的時間會受到渲染物體的時間影響(LateUpdate是在所有的Update方法執行完後再執行),打個比方說:相同的遊戲,在性能好的機器上可以跑60幀每秒,但是在差的機器上,可能只能跑30幀每秒.兩者相差了1倍,甚至更多.

FixedUpdate是固定頻率更新,常常用來處理Unity中物理相關的東西,它不受渲染效率的影響,以固定的時間間隔調用,

所以為了保證服務端和客戶端的模擬頻率一致,那麼在Unity中,就選用FixedUpdate方法.在Unity中可以在Edit->Project Setting->time中找到Fixed timestep進行修改,也可以在代碼中設置Time.fixedDeltaTime的值.

public void SetFixedDeltaTimeForServer ()
{
Time.fixedDeltaTime = 1f/60; //當伺服器成功啟動,設置FixedUpdate更新間隔為每秒60次
}

public void SetFixedDeltaTimeForClient()
{
Time.fixedDeltaTime = 1f/60; //與服務端保持一致
}

這樣,伺服器和客戶端的FixedUpdate方法都會按照相同的頻率調用,然後把操作的模擬(Simulate)放在裡面執行.

2.相同的狀態 + 相同的操作指令 = 相同的新狀態

為了讓服務端和客戶端模擬的結果相同,首先必須保證服務端和客戶端的模擬邏輯代碼一致,盡量減少使用默認的物理模擬(PS:引擎的物理模擬有些會帶有隨機數,一旦伺服器和客戶端的隨機數不一致,會導致結果不一致),先來定義操作指令類(Command)

public class Command
{
public uint sequence; //指令序號

public CommandInput input; //操作指令的輸入

public CommandResult result; //操作指令執行後得到的結果
}

Simulate方法需要做的應該就是收集操作指令CommandInput,然後執行,得到CommandResult

public void FixedUpdate()
{
Simulate();
}

public void Simulate()
{
OnSimulateBefore();

if(isServer && isOwner) //如果是伺服器的物體,獲取指令,直接執行指令即可
{
Command cmd = new Command ();
cmd.input = CollectCommandInput(); // 獲取指令
ExecuteCommand(cmd); // 執行指令
}

OnSimulateAfter();
}

public override void ExecuteCommand(Command command)
{
float movingSpeed = 4;
Vector3 movingDir = Vector3.zero;

if (input.forward ^ input.backward)
movingDir.z = input.forward ? +1 : -1;

if (input.left ^ input.right)
movingDir.x = input.right ? +1 : -1;

Vector3 velocity = movingDir * movingSpeed; //通過輸入計算出速度

transform.position = transform.position + velocity * Time.fixedDeltaTime; //立即計算出結果

command.result.position = transform.position; //將結果保存到CommandResult中

}

CollectCommandInputExecuteCommand方法中,客戶端和服務端的代碼應該是一致的.

伺服器和客戶端,執行完Command以後,填充result需要的數據.這樣,一個Command就完成了,經過網路同步以後,利用sequence(指令序號)來對比操作的結果是否一致.

操作結果如果:

3.小結

有了這個基本的Command的結構和相同頻率的Simulate,後續就要考慮服務端和客戶端如何去同步這些Command.

推薦閱讀:

相关文章