unity-unet-多人在线同步问题解决方案
- 看了些文章,大牛對(duì)同問(wèn)題的解決方案
- 傳送門:Fast-Paced Multiplayer
文中大體的思路:
A玩家 移動(dòng)時(shí),本機(jī)自行移動(dòng),并發(fā)送移動(dòng)指令給服務(wù)端,假設(shè)移動(dòng)是成功的,服務(wù)端同步其他客戶端 B玩家,B玩家 中用一個(gè)隊(duì)列 Queue 來(lái)裝服務(wù)端來(lái)的移動(dòng)指令,然后客戶端在updata中做插值 (lerp ) 處理,這樣 A玩家 在 B玩家客戶端中移動(dòng)起來(lái)就比較平滑
如果 A玩家 移動(dòng)很頻繁,B玩家 中的 指令隊(duì)列 Queue 會(huì)堆積的很大,這里可以做個(gè)優(yōu)化,就是當(dāng) Queue 的 size 超過(guò)某個(gè)臨界值 (threshold)時(shí),加快插值(lerp)的速率
A玩家 移動(dòng)時(shí),本機(jī)自行移動(dòng) 并保留一份此次移動(dòng)的 副本 (copy)到一個(gè) 隊(duì)列 中,并發(fā)送移動(dòng)指令給服務(wù)端,如果服務(wù)端判定移動(dòng)是失敗的(比如穿墻之類的),則服務(wù)端下發(fā)指令給 A玩家 修復(fù)此次移動(dòng)的位置,然后 隊(duì)列 中移除此次移動(dòng)的副本
關(guān)于攻擊時(shí)的同步,客戶端A 中自行播放攻擊動(dòng)作并上行給服務(wù)的此次攻擊的指令,服務(wù)端同步其他 客戶端B 播放攻擊動(dòng)作,同時(shí)同步給所有客戶端(客戶端A和B)扣血指令,為防止客戶端作弊必須有服務(wù)端運(yùn)行計(jì)算實(shí)際扣血量。
下面是部分關(guān)于位置同步的代碼
using UnityEngine; using System.Collections; using UnityEngine.Networking; using System.Collections.Generic;/// <summary> /// 可以通過(guò) /// 1. 減少發(fā)包率(意思就是 增大 sendInterval 發(fā)包間隔) /// 2. 增大 closeEnough 距離 /// 3. 增大 normalLerpRate、fasterLerpRate 插值速率 /// </summary>[NetworkSettings(channel = 0, sendInterval = 0.1f)] public class SmoothMove : NetworkBehaviour {[SyncVar(hook = "SyncPostionsValues")]private Vector3 syncPos; //同步變量[SerializeField]Transform myTransform; //SerializeField用于inspector中顯示非public變量private float lerpRate;private float normalLerpRate = 16.0f;private float fasterLerpRate = 27.0f;private Vector3 lastPos;private float threshold = 0.5f;private List<Vector3> syncPosList = new List<Vector3>();[SerializeField]private bool useHistoriicalLerping = false; //是否啟用平滑插值的開關(guān),直接在 inspector 中設(shè)置private float closeEnough = 0.11f;public void Start(){lerpRate = normalLerpRate;}public void Update(){LerpPosition(); //因?yàn)榉椒ɡ昧薚ime.deltaTime,所以只能在 Updata中調(diào)用}public void FixedUpdate() //1. server 和 client 都執(zhí)行FixedUpdate{TransmitPosition(); //2. 因?yàn)槭?ClientCallback,所以只有客戶端調(diào)用}void LerpPosition(){if (!isLocalPlayer) //5. 只有非本機(jī)玩家才進(jìn)行插值移動(dòng)到最新的 syncPos 位置{if (useHistoriicalLerping) //更加平滑{HistoryLerping();}else{OrdinaryLerping();}}}[Command]void CmdProvidePositionToServer(Vector3 pos){syncPos = pos; //4. 服務(wù)端收到信息同步給所有客戶端的該對(duì)象的syncPos變量}[Client]void TransmitPosition(){if (isLocalPlayer && Vector3.Distance(myTransform.position, lastPos) > threshold) //3. 只用本機(jī)玩家才提交位置信息到server上{CmdProvidePositionToServer(myTransform.position);}}[Client]public void SyncPostionsValues(Vector3 lastPos){syncPos = lastPos;syncPosList.Add(syncPos); //將所有服務(wù)端同步過(guò)來(lái)的 pos 全都保存在隊(duì)列中}void OrdinaryLerping() //普通插值,有卡頓現(xiàn)象{myTransform.position = Vector3.Lerp(myTransform.position, syncPos, Time.deltaTime * lerpRate);}void HistoryLerping() //平滑插值{if (syncPosList.Count > 0){//取出隊(duì)列中的第一個(gè)設(shè)為插值的目標(biāo)myTransform.position = Vector3.Lerp(myTransform.position, syncPosList[0], Time.deltaTime * lerpRate);//位置足夠接近,從隊(duì)列中移除第一個(gè),緊接著就是第二個(gè)if (Vector3.Distance(myTransform.position, syncPosList[0]) < closeEnough){syncPosList.RemoveAt(0);}//如果同步隊(duì)列過(guò)大,加快插值速率,使其更快到達(dá)目標(biāo)點(diǎn)if (syncPosList.Count > 10){lerpRate = fasterLerpRate;}else{lerpRate = normalLerpRate;}Debug.LogFormat("--- syncPosList, count:{0}", syncPosList.Count);}} }總結(jié)
以上是生活随笔為你收集整理的unity-unet-多人在线同步问题解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 电脑中的"倚天剑+屠龙刀"【推荐】
- 下一篇: java新手初次面试要注意的事项