Unity中网络游戏肯定要考虑时间的同步问题,因为每个网络客户端因为网络的延迟不一造成进入游戏主界面的时间不一样,如果不考虑解决这个问题,就会造成不同客户端的游戏时间不同步,比如倒计时可能就会有先有后,这肯定不能满足游戏的要求。以我现在开发的网络对战游戏主题游戏为例,相对来说这个案例具有一定的通用参考价值,游戏实现的逻辑应该是:允许不一样网速或者客户端(当然我的游戏支持多客户端,这个根据游戏开发定位而定)据实加入游戏,在进入选择角色配置一些游戏信息后,选择某个游戏房间点击开始,在所有房间玩家都点击准备后,主客户端(担当服务端功能角色isMasterClient)玩家点击开始游戏,所有玩家进入下一个游戏场景的时间由于加载问题肯定会出现不一致,当然有人会问在同一场景中难道就不存在不同步问题了吗?这个是刷新帧率问题,update,fixupdate,lateupdate这些使用自己可以查文档,这个同步默认你已理解掌握。这时的解决办法很重要。干货,直接上方案:
1.在进入房间的场景中重写onjoinedroom函数。
public override void OnJoinedRoom()
{
Hashtable props = new Hashtable
{
{AsteroidsGame.PLAYER_LOADED_LEVEL, false}
};
PhotonNetwork.LocalPlayer.SetCustomProperties(props);
}
2.在游戏主场景的脚本中添加:
public void Start()
{
Hashtable props = new Hashtable
{
{AsteroidsGame.PLAYER_LOADED_LEVEL, true}
};
PhotonNetwork.LocalPlayer.SetCustomProperties(props);
}
解释一下:当开始执行时说明游戏主场景当前玩家已经进入,将玩家AsteroidsGame.PLAYER_LOADED_LEVEL属性设为true
3.重写个人更新信息函数 OnPlayerPropertiesUpdate
public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
{
if (!PhotonNetwork.IsMasterClient)
{
return;
}
//前提是服务器端角色客户端来设置房间信息。。。
if (changedProps.ContainsKey(AsteroidsGame.PLAYER_LOADED_LEVEL))
{
if (CheckAllPlayerLoadedLevel())
{
Hashtable props = new Hashtable
{
{CountdownTimer.CountdownStartTime, (float) PhotonNetwork.Time}
};
PhotonNetwork.CurrentRoom.SetCustomProperties(props);
}
}
}
注释:当有玩家进入状态有变化时更新信息,当一个玩家start后PLAYER_LOADED_LEVEL属性为真,记录此时玩家进入房间的服务器统一时间,作为当前玩家客户端进入主场景的开始时间,作为游戏时间同步使用。
4.在主场景另外的时间控制脚本中:Update中增加触发事件的逻辑
public void Update()
{
if (!isTimerRunning)
{
}
float timer = (float)PhotonNetwork.Time - startTime;
float countdown = Countdown - timer;
Text.text = string.Format("Game starts in {0} seconds", countdown.ToString("n2"));
if (countdown > 0.0f)
{
return;
}
isTimerRunning = false;
Text.text = string.Empty;
if (OnCountdownTimerHasExpired != null)
{
OnCountdownTimerHasExpired();//到时间逻辑时,触发事件,此事件在游戏主脚本中
}
}
游戏主脚本中对事件进行注册和处理
public override void OnEnable()
{
base.OnEnable();
CountdownTimer.OnCountdownTimerHasExpired += OnCountdownTimerIsExpired;
}
public override void OnDisable()
{
base.OnDisable();
CountdownTimer.OnCountdownTimerHasExpired -= OnCountdownTimerIsExpired;
}
private void OnCountdownTimerIsExpired()
{
StartGame();
}
5.时间控制脚本中,房间信息有更新时检查OnRoomPropertiesUpdate
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
object startTimeFromProps;
if (propertiesThatChanged.TryGetValue(CountdownStartTime, out startTimeFromProps))
{
isTimerRunning = true;
startTime = (float)startTimeFromProps;
}
}
此时获得的游戏开始时间是所有玩家进入房间后的统一时间,作为同步时间用。