【锁定帧同步Lockstep】客户端逻辑

2022-04-16  本文已影响0人  木心Sepith

服务器逻辑很简单,逻辑帧以固定频率(一般为每秒20帧,也就是0.05s一帧)进行Tick,
每个Tick必须等待所有玩家的操作到达后才可执行

锁定帧同步客户端逻辑代码


using System.Collections.Generic;
using UnityEngine;

namespace FrameTest
{
    public struct OperationList
    {
        /// <summary>
        /// 帧索引
        /// </summary>
        public int frameIndex;
        /// <summary>
        /// 帧操作列表
        /// </summary>
        public Operation[] operations;
    }

    public struct Operation
    {
        /// <summary>
        /// 玩家唯一标识
        /// </summary>
        public int uid;
        /// <summary>
        /// 玩家输入方向
        /// </summary>
        public Net.Vector3 direction;
    }

    public class Game
    {
        public List<Player> players = new List<Player>();

        public Player FindPlayer(int uid)
        {
            return players.Find(p => p.uid == uid);
        }
    }

    public class Player
    {
        public int uid;

        public void Move(Net.Vector3 direction)
        {
            //move
        }
    }

    public static class InputDetect
    {
        public static Net.Vector3 GetCurFrameDirection()
        {
            var direction = new Net.Vector3(Input.GetAxis("Horizontal").ToFloat(100), 0f, Input.GetAxis("Vertical").ToFloat(100));

            return direction;
        }
    }

    /// <summary>
    /// lockstep
    /// </summary>
    public class Test : MonoBehaviour
    {
        /// <summary>
        /// 本地消息帧号,收到一条消息自增
        /// </summary>
        private int localOperationFrame;

        /// <summary>
        /// 本地快照
        /// </summary>
        private List<OperationList> snapshots = new List<OperationList>();

        /// <summary>
        /// 本地逻辑帧号
        /// </summary>
        private int localLogicFrame;

        /// <summary>
        /// 本场对局数据
        /// </summary>
        private Game game;

        /// <summary>
        /// 初始化
        /// </summary>
        void Init()
        {
            localOperationFrame = 0;
            snapshots.Clear();
            localLogicFrame = 0;
            game = new Game();
        }

        /// <summary>
        /// 收到帧消息
        /// </summary>
        /// <param name="list"></param>
        public void OnOperationSync(OperationList list)
        {
            if (localOperationFrame != list.frameIndex)
            {
                Debug.Log($"帧号不一致!本地帧号:{localOperationFrame},消息帧号:{list.frameIndex}");
                return;
            }

            //本地消息帧号自增
            localOperationFrame++;

            //本地缓存
            snapshots.Add(list);

            Operation op = new Operation();
            op.direction = InputDetect.GetCurFrameDirection();
            //SendOperationMsgToServer(op);
        }

        private void Update()
        {
            //剩余几帧未播放
            int leftFrame = localOperationFrame - localLogicFrame;

            //播放
            for (int i = 0; i < leftFrame; i++)
            {
                var list = snapshots[localLogicFrame];

                TickLogicFrame(list);

                localLogicFrame++;
            }
        }

        /// <summary>
        /// 处理逻辑帧
        /// </summary>
        private void TickLogicFrame(OperationList list)
        {
            //do logic...
            for (int i = 0; i < list.operations.Length; i++)
            {
                //player move
                var op = list.operations[i];
                var player = game.FindPlayer(op.uid);
                player.Move(op.direction);
            }
        }
    }

}

上一篇 下一篇

猜你喜欢

热点阅读