1. 肯定本局随机种子服务器
因为即时对战游戏中有不少随机的事件,同一个随机事件(好比MOBA中的暴击)不能由于是不一样的机器就得出不一样的结果。因此在某一局的开始时就肯定一个固定的时间种子,可使用当前的时间戳做为种子(通常以服务器时间)。dom
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); System.Random random = new System.Random((int)ts.TotalSeconds); for (int i = 0; i < 10; i++) { Debug.Log(random.Next(1, 1000)); //从1-999中随机一个数 }
由服务器将服务器时间戳发送到各个客户端(果如以为太大能够用65536取个余),若是须要回放功能只要保存服务器发送的时间戳便可。oop
2. 游戏循环和插值计算code
咱们假设作一个物体移动的功能,如下是核心逻辑代码:orm
private bool m_bIsLoop = false; //是否循环 private int m_iLogicFrameCount; //逻辑帧数计数 private const int m_kFRAME_UPDATE_MS = 50; //正常逻辑中更新间隔(毫秒),设50毫秒由于MOBA通常设的是50 private const int m_kFRAME_UPDATE_MS_SLOW = 500; //慢速逻辑中更新间隔(毫秒) private int m_iFrameUpdateMS; //实际逻辑中更新间隔(毫秒) private int m_iLag; //据上一个逻辑帧的间隔(毫秒) private float m_fInterpolation; //插值百分比 [SerializeField] private GameObject g; //模拟移动的物体 private Vector3 m_v3LogicPosition; //物体逻辑帧的位置 private const float m_kSpeed = 0.1f; //物体移动速度(每一个逻辑帧) void Loop() //逻辑帧计算 { m_v3LogicPosition = m_v3LogicPosition + Vector3.right * m_kSpeed; //物体逻辑帧的位置移动m_kSpeed的距离 g.transform.localPosition = m_v3LogicPosition; //物体的位置设为逻辑帧计算获得的位置 if(m_iLogicFrameCount >= 2) //两秒以后进入慢速模式(子弹时间) { m_iFrameUpdateMS = m_kFRAME_UPDATE_MS_SLOW; } } void Interpolation() //插值计算 { //根据插值百分比计算插值位置 g.transform.localPosition = Vector3.Lerp(m_v3LogicPosition, m_v3LogicPosition + Vector3.right * m_kSpeed, m_fInterpolation); } void FixedUpdate() { if (!m_bIsLoop) return; if (m_iLag < m_iFrameUpdateMS) //据上一个逻辑帧的间隔小于固定更新间隔 { m_iLag += (int)(Time.fixedDeltaTime * 1000); m_fInterpolation = (float)m_iLag / m_iFrameUpdateMS; //计算插值百分比 Interpolation(); } else //据上一个逻辑帧的间隔大于固定更新间隔,执行一次逻辑帧计算 { m_iLogicFrameCount++; m_iLag -= m_iFrameUpdateMS; Loop(); } }
FixedUpdate里只会写物理运动和与游戏相关的逻辑,另外一些与游戏逻辑无关的能够写到Update里面去(好比Dota里面树木的晃动,河道水流的运动等)。作到这里我想到是否是能够经过这段代码实现子弹时间功能?因而我稍做修改添加了m_kFRAME_UPDATE_MS_SLOW这个常量,而且在两个逻辑帧后将逻辑帧更新间隔设成这个慢速的,即可以看出物体的移动速度只有原来的十分之一(因此猜测咱们用m_kFRAME_UPDATE_MS来处理主角的逻辑是否是就能够实现相似荒野大镖客2里的子弹时间功能,联想Dota里面暂停的时候树木的晃动和河道的运动并无变化,因此进一步证实了他们的逻辑是在Update里处理的)。游戏
3. 游戏里输入的处理事件
以上面的代码为基础,假设咱们改变一下需求,按下键盘上的上下左右方向键能够改变物体的移动方向,都不按时物体不移动,实现时要考虑到客户端服务器间交互的延迟。猜测若是有多个客户端估计还要给每一个客户端一个ID,客户端和服务器都要管理这个客户端List。客户端发送输入时要带上本身的ID信息,同时服务器通知各个客户端时也要带上每一个输入是针对的哪一个客户端的信息。it
再一个要着重考虑就是输入顺序的管理。io
首先是同一客户端的输入顺序,假如客户端5毫秒时发送了向左的输入,10毫秒时发送了向右的输入,按道理客户端最终的状态应该是向右,但是若是考虑到延迟,向左的输入在45毫秒时被服务器收到,向右的输入在40毫秒时被服务器收到,那么服务器通知客户端的方向就变成了向左,显然这是错误的。form
再者就是不一样客户端的输入顺序,假若有两个客户端A和B,A在第5毫秒攻击了B,B在第10毫秒攻击了A,两人都是一击毙命。若是服务器通知各个客户端输入时没有标注这两个输入谁先谁后,各个客户端Update以后的结果可能都会不一样。
游戏里输入的处理之后有机会再补充吧。