关于Unity的回放功能(二)

5 篇文章 1 订阅

关于Unity的回放功能(二)

前言

上次因为公司项目没有完全展开,所以上次写的回放功能不是最终的版本,现在有时间,可以将回放功能所用到的内容从新整理记录一下。用于以后做参考。在上一篇文章中写了一部分了,具体可以查看上一篇文章,这次是对上一篇文章进行更加细化的整理和编写。其中有一部分涉及到了公司项目,所以有报错的地方,但是思路的话还是比较清晰的。
直接上代码

 using Common;
using DG.Tweening;
//using Net.Share;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UI;
using UnityEngine;
using UnityEngine.UI;
//用于控制回放时各个UI按钮及玩家移动的类
using Common;
using DG.Tweening;
//using Net.Share;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UI;
using UnityEngine;
using UnityEngine.UI;

public class ReplayManager : MonoSingleton<ReplayManager>
{
    public ReplayPanel replayPanel;
    public ReplayData data;//首次所用data数据
    public bool rePlay;
    public float timer;
    //按下按键时间,用于玩家按下、抬起WASD按键
    public List<float> pressTimeW, liftUpTimeW;
    public List<float> pressTimeA, liftUpTimeA;
    public List<float> pressTimeS, liftUpTimeS;
    public List<float> pressTimeD, liftUpTimeD;
    public List<float> mouseDownTime, mouseUpTime;
    //这个时间的话是判断在按下、抬起WASD按键的过程中间隔是多久,通过时间差来回放玩家的移动
    float Wtime;
    float Atime;
    float Stime;
    float Dtime;
    float rotationTime;
    /// <summary>
    /// 玩家移动类
    /// </summary>
    public PlayerMove playerMove;
    public float replaySpeed = 1;//回放速度
    public float totalTimer = 0;//回放的总时长
    /// <summary>
    /// 提示框
    /// </summary>
    public GameObject message;
    protected override void Initialize()
    {
        data = new ReplayData();
        pressTimeW = new List<float>();
        liftUpTimeW = new List<float>();
        pressTimeA = new List<float>();
        liftUpTimeA = new List<float>();
        pressTimeS = new List<float>();
        liftUpTimeS = new List<float>();
        pressTimeD = new List<float>();
        liftUpTimeD = new List<float>();
        mouseDownTime = new List<float>();
        mouseUpTime = new List<float>();
        playerMove = GameObject.FindObjectOfType<PlayerMove>();

    }
    public float replayTimer;
    protected override void Awake()
    {
        base.Awake();



    }
    /// <summary>
    /// 判断回放是否完成
    /// </summary>
    public bool isFinish = false;
    private void Update()
    {
        if (!rePlay)
        {

            timer += Time.deltaTime * replaySpeed;

        }
        if (rePlay)
        {
            if (replayTimer >= data.totalTimer)
            {
                isFinish = true;
                if (isFinish == true)
                {
                    message.SetActive(true);
                    replayPanel.totalTime = "";
                    message.transform.Find("GameObject/Content").GetComponent<Text>().text = "流程回放已结束,请退出该任务流程回放";
                    //在这里要设置一下
                    replayPanel.transform.Find("Buttons").gameObject.SetActive(false);
                }
                rePlay = false;
            }

            replayTimer += Time.deltaTime * replaySpeed;

            StartReplayProgress();
        }
    }
    /// <summary>
    /// 这里是在回放过程中,对按钮的事件进行复现的功能,复现完成后,删除对应的按钮事件
    /// </summary>
    private void StartReplayProgress()
    {
        for (int i = 0; i < UIManager.Instance.buttonEventTime.Count; i++)
        {
            if (UIManager.Instance.buttonEventTime[i] < replayTimer)
            {
                //如果小于的话,直接删除这个元素
                foreach (var button in UIManager.Instance.buttons)
                {
                    try
                    {
                        if (button == null) continue;
                        if (button.name == data.buttonDic[UIManager.Instance.buttonEventTime[i]])
                        {
                            button.onClick.Invoke();
                            UIManager.Instance.buttonEventTime.Remove(UIManager.Instance.buttonEventTime[i]);
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.Log(button.name);
                        Debug.Log(e.ToString());
                    }

                }
            }
        }
        for (int i = 0; i < UIManager.Instance.inputFieldTime.Count; i++)
        {
            if (UIManager.Instance.inputFieldTime[i] < replayTimer)
            {
                //如果小于的话,直接删除这个元素
                foreach (var input in UIManager.Instance.inputFields)
                {
                    if (input == null) continue;
                    foreach (var name in data.inputFieldDic[UIManager.Instance.inputFieldTime[i]].Keys)
                    {
                        if (input.name == name)
                        {
                            try
                            {
                                input.onValueChanged.Invoke(data.inputFieldDic[UIManager.Instance.inputFieldTime[i]][UIManager.Instance.inputFieldName[i]]);
                                UIManager.Instance.inputFieldName.Remove(name);
                                UIManager.Instance.inputFieldTime.Remove(UIManager.Instance.inputFieldTime[i]);
                                return;
                            }
                            catch (Exception e)
                            {
                                Debug.Log(e.ToString());
                            }

                        }
                    }
                }
            }
        }
        //对回放的InputToggle进行复现
        for (int i = 0; i < UIManager.Instance.inputToggleTime.Count; i++)
        {
            if (UIManager.Instance.inputToggleTime[i] < replayTimer)
            {
                //如果小于的话,直接删除这个元素
                foreach (var toggle in UIManager.Instance.toggles)
                {
                    if (toggle == null) continue;
                    foreach (var name in data.toggleDic[UIManager.Instance.inputToggleTime[i]].Keys)
                    {
                        //如果InputToggle的名字重复的话,有时候就会判断错误,所以需要给他再添加一个判定方式
                        //这里用增加一个父物体来进行判定
                        if (toggle.transform.parent.name + toggle.name == name)
                        {
                            try
                            {
                                Debug.Log("当前Toggle的IsOn为:" + data.toggleDic[UIManager.Instance.inputToggleTime[i]][UIManager.Instance.togglesName[i]]);
                                toggle.isOn = data.toggleDic[UIManager.Instance.inputToggleTime[i]][UIManager.Instance.togglesName[i]];
                                toggle.onValueChanged.Invoke(data.toggleDic[UIManager.Instance.inputToggleTime[i]][UIManager.Instance.togglesName[i]]);
                                UIManager.Instance.inputToggleTime.Remove(UIManager.Instance.inputToggleTime[i]);
                                UIManager.Instance.togglesName.Remove(UIManager.Instance.togglesName[i]);
                                return;
                            }
                            catch (Exception e)
                            {
                                Debug.Log(e.ToString());
                            }

                        }
                    }
                }
            }
        }
        //对回放的DropDown的按钮进行复现
        for (int i = 0; i < UIManager.Instance.dropDownTime.Count; i++)
        {
            if (UIManager.Instance.dropDownTime[i] < replayTimer)
            {
                //如果小于的话,直接删除这个元素
                foreach (var dropdown in UIManager.Instance.dropdowns)
                {
                    if (dropdown == null) continue;
                    foreach (var name in data.dropDownDic[UIManager.Instance.dropDownTime[i]].Keys)
                    {
                        //如果Toggle的名字重复的话,有时候就会判断错误,所以需要给他再添加一个判定方式
                        //这里用增加一个父物体来进行判定
                        if (dropdown.transform.parent.name + dropdown.name == name)
                        {
                            try
                            {
                                dropdown.value = data.dropDownDic[UIManager.Instance.dropDownTime[i]][name];
                                dropdown.onValueChanged.Invoke(data.dropDownDic[UIManager.Instance.dropDownTime[i]][name]);
                                UIManager.Instance.dropDownTime.Remove(UIManager.Instance.dropDownTime[i]);
                                UIManager.Instance.dropDownName.Remove(UIManager.Instance.dropDownName[i]);
                                return;
                            }
                            catch (Exception e)
                            {
                                Debug.Log(e.ToString());
                            }

                        }
                    }
                }
            }
        }
      
        for (int i = 0; i < pressTimeA.Count; i++)
        {
            if (pressTimeA[i] < replayTimer)//当前时间如果大于按下的时间的话,那么就调用人物移动的方法
            {
                if (pressTimeA[i] < liftUpTimeA[i])
                {
                    Atime += Time.deltaTime * replaySpeed;
                    if (Atime < liftUpTimeA[i] - pressTimeA[i])
                    {
                        playerMove.transform.Translate(-data.AoriginPlayerTimeAndSpeedDic[pressTimeA[i]] * replaySpeed, 0, 0, Space.Self);
                    }
                    else
                    {
                        pressTimeA.Remove(pressTimeA[i]);
                        liftUpTimeA.Remove(liftUpTimeA[i]);
                        Atime = 0;
                        return;
                    }
                }

            }
        }
        for (int i = 0; i < pressTimeW.Count; i++)
        {
            if (pressTimeW[i] < replayTimer)//当前时间如果大于按下的时间的话,那么就调用人物移动的方法
            {
                if (pressTimeW[i] < liftUpTimeW[i])
                {
                    Wtime += Time.deltaTime * replaySpeed;
                    if (Wtime < liftUpTimeW[i] - pressTimeW[i])
                    {
                        playerMove.transform.Translate(0, 0, data.WoriginPlayerTimeAndSpeedDic[pressTimeW[i]] * replaySpeed, Space.Self);
                    }
                    else
                    {
                        pressTimeW.Remove(pressTimeW[i]);
                        liftUpTimeW.Remove(liftUpTimeW[i]);
                        Wtime = 0;
                        return;
                    }
                }

            }
        }
        for (int i = 0; i < pressTimeS.Count; i++)
        {
            if (pressTimeS[i] < replayTimer)//当前时间如果大于按下的时间的话,那么就调用人物移动的方法
            {
                if (pressTimeS[i] < liftUpTimeS[i])
                {
                    Stime += Time.deltaTime * replaySpeed;
                    if (Stime < liftUpTimeS[i] - pressTimeS[i])
                    {
                        playerMove.transform.Translate(0, 0, -data.SoriginPlayerTimeAndSpeedDic[pressTimeS[i]] * replaySpeed, Space.Self);
                    }
                    else
                    {
                        pressTimeS.Remove(pressTimeS[i]);
                        liftUpTimeS.Remove(liftUpTimeS[i]);
                        Stime = 0;
                        return;
                    }
                }

            }
        }
        for (int i = 0; i < pressTimeD.Count; i++)
        {
            if (pressTimeD[i] < replayTimer)//当前时间如果大于按下的时间的话,那么就调用人物移动的方法
            {
                if (pressTimeD[i] < liftUpTimeD[i])
                {
                    Dtime += Time.deltaTime * replaySpeed;
                    if (Dtime < liftUpTimeD[i] - pressTimeD[i])
                    {
                        playerMove.transform.Translate(data.DoriginPlayerTimeAndSpeedDic[pressTimeD[i]] * replaySpeed, 0, 0, Space.Self);
                    }
                    else
                    {
                        pressTimeD.Remove(pressTimeD[i]);
                        liftUpTimeD.Remove(liftUpTimeD[i]);
                        Dtime = 0;
                        return;
                    }
                }

            }
        }

        for (int i = 0; i < mouseUpTime.Count; i++)
        {
            if (mouseUpTime[i] < replayTimer)//当前时间如果大于按下的时间的话,那么就调用人物旋转的方法
            {
                if ((i + 1) < mouseUpTime.Count)
                {
                    rotationTime = mouseUpTime[i + 1] - mouseUpTime[i];
                    playerMove.transform.DORotate(new Vector3(data.playerUpRotX[mouseUpTime[i]], data.playerUpRotY[mouseUpTime[i]], data.playerUpRotZ[mouseUpTime[i]]), rotationTime / (replaySpeed));
                    data.playerUpRotX.Remove(mouseUpTime[i]);
                    data.playerUpRotY.Remove(mouseUpTime[i]);
                    data.playerUpRotZ.Remove(mouseUpTime[i]);
                    mouseUpTime.Remove(mouseUpTime[i]);
                }
            }
        }
    }
    //重新回放时清除之前所有的数据
    public void ClearData()
    {
        UIManager.Instance.buttonEventTime.Clear();
        UIManager.Instance.inputFieldTime.Clear();
        UIManager.Instance.inputFieldName.Clear();
        UIManager.Instance.inputToggleTime.Clear();
        UIManager.Instance.dropDownTime.Clear();
        UIManager.Instance.togglesName.Clear();
        UIManager.Instance.dropDownName.Clear();
        UIManager.Instance.goChangeTime.Clear();
        pressTimeW.Clear();
        liftUpTimeW.Clear();
        pressTimeA.Clear();
        liftUpTimeA.Clear();
        pressTimeS.Clear();
        liftUpTimeS.Clear();
        pressTimeD.Clear();
        liftUpTimeD.Clear();
        mouseUpTime.Clear();
      
        //在这里首先判断出来是否有任务准备和射后恢复阶段
        string Processcontent = "";       
    }
    
    public void GetData(ReplayData data)
    {
        //根据得到的所有命令,在这里开始播放

        foreach (var item in data.buttonDic.Keys)
        {
            UIManager.Instance.buttonEventTime.Add(item);
        }
        foreach (var item in data.inputFieldDic.Keys)
        {
            UIManager.Instance.inputFieldTime.Add(item);
        }
        foreach (var item in data.inputFieldDic.Keys)
        {
            foreach (var name in data.inputFieldDic[item].Keys)
            {
                UIManager.Instance.inputFieldName.Add(name);
            }
        }
        foreach (var item in data.toggleDic.Keys)
        {
            UIManager.Instance.inputToggleTime.Add(item);
        }
        foreach (var item in data.toggleDic.Keys)
        {
            foreach (var name in data.toggleDic[item].Keys)
            {
                UIManager.Instance.togglesName.Add(name);
            }
        }
        foreach (var item in data.dropDownDic.Keys)
        {
            foreach (var name in data.dropDownDic[item].Keys)
            {
                UIManager.Instance.dropDownName.Add(name);
            }
        }
        foreach (var item in data.goNameDic.Keys)
        {
            UIManager.Instance.goChangeTime.Add(item);
        }
        foreach (var item in data.dropDownDic.Keys)
        {
            UIManager.Instance.dropDownTime.Add(item);
        }
        //得到所有移动和旋转按键按下时的时间
        foreach (var item in data.WoriginPlayerTimeAndSpeedDic.Keys)
        {
            pressTimeW.Add(item);
        }
        foreach (var item in data.WendPlayerTimeAndSpeedDic.Keys)
        {
            liftUpTimeW.Add(item);
        }
        foreach (var item in data.AoriginPlayerTimeAndSpeedDic.Keys)
        {
            pressTimeA.Add(item);
        }
        foreach (var item in data.AendPlayerTimeAndSpeedDic.Keys)
        {
            liftUpTimeA.Add(item);
        }
        foreach (var item in data.SoriginPlayerTimeAndSpeedDic.Keys)
        {
            pressTimeS.Add(item);
        }
        foreach (var item in data.SendPlayerTimeAndSpeedDic.Keys)
        {
            liftUpTimeS.Add(item);
        }
        foreach (var item in data.DoriginPlayerTimeAndSpeedDic.Keys)
        {
            pressTimeD.Add(item);
        }
        foreach (var item in data.DendPlayerTimeAndSpeedDic.Keys)
        {
            liftUpTimeD.Add(item);
        }
        foreach (var item in data.playerUpRotX.Keys)
        {
            mouseUpTime.Add(item);
        }
        //在这里让replayPanel出现
        replayPanel.gameObject.SetActive(true);
        this.data = data;
    }
    //开始回放
    public void StartProcess()
    {
        replayTimer = 0;
        rePlay = true;
    }
    //获取所有的玩家位置
    public void GetCurrentPos(Dictionary<float, float> playerPosX, Dictionary<float, float> playerPosY, Dictionary<float, float> playerPosZ)
    {
        playerPosX.Add(timer, transform.position.x);
        playerPosY.Add(timer, transform.position.y);
        playerPosZ.Add(timer, transform.position.z);
    }
   //从服务器得到之前保存的回放数据
    //[Rpc]
    public void GetFirstRePlayDataResult(ReplayData data)
    {
        this.data = data;
        Debug.Log("得到文件成功");
        GetData(this.data);
        //获取之前保存的回放时的总时长
        replayPanel.totalTime = FormatNumberDateTime(((int)data.totalTimer).ToString());
    }
    /// <summary>
    /// 秒转换成时分秒(分的)
    /// </summary>
    /// <param name="secondTime"></param>
    /// <returns></returns>
    public string FormatNumberDateTime(string secondTime)
    {
        if (string.IsNullOrEmpty(secondTime))
        {
            return "";
        }
        else
        {
            long mss = long.Parse(secondTime);

            string DateTimes = null;
            long days = mss / (60 * 60 * 24);
            long hours = (mss % (60 * 60 * 24)) / (60 * 60);
            long minutes = (mss % (60 * 60)) / 60;
            long seconds = mss % 60;

            if (minutes > 0)
            {
                DateTimes = minutes + ":" + seconds;
            }
            else
            {
                DateTimes = "00:" + seconds;
            }
            return DateTimes;
        }
    }
}

接下来是UI面板控制回放

using MVC;
//using Net.Share;
using System;
using System.Collections;
using System.Collections.Generic;
using UI;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;

public class ReplayPanel : BasePanel
{    //                 开始流程    重新开始流程
    private Button startProcessBtn, reStartProcess;
    private Button returnProcessBtn;//退出回放流程
    private Text speedText, totalTimeText;
    protected override void Awake()
    {
        base.Awake();
        InitComponent();
        AddListener();

    }
    public override void InitComponent()
    {
        base.InitComponent();
        startProcessBtn = transform.Find("StartProcessBtn").GetComponent<Button>();
        returnProcessBtn = transform.Find("ReturnProcessBtn").GetComponent<Button>();
        reStartProcess = transform.Find("ReStartProcessBtn").GetComponent<Button>();
        speedText = transform.Find("Buttons/Speed").GetComponent<Text>();
        totalTimeText = transform.Find("Buttons/总时长").GetComponent<Text>();
    }
    public string totalTime;
    //当前回放时间
    public float timer;
    private void Start()
    {
        reStartProcess.gameObject.SetActive(false);
        //向服务器获取保存的回放数据             玩家用户名                        任务名称                      第几次回放
        Send("GetRePlayData", LoginManager.instance.replayAcc, NetworkManager.instance.taskName, LoginManager.instance.replayNumber, true);//在这里得到具体哪一次的回放


    }
    private void Update()
    {
        if (ReplayManager.Instance.rePlay)
        {
            timer += Time.deltaTime * ReplayManager.Instance.replaySpeed;
            long minutes = ((long)timer % (60 * 60)) / 60;
            long seconds = (long)timer % 60;
            totalTimeText.text = string.Format("{0:D2}:{1:D2}", minutes, seconds) + "/" + totalTime;
        }
    }
    public override void AddListener()
    {
        base.AddListener();
        //在这里的话之前还有暂停、继续、加速、减速回放过程,因为涉及到项目内容,所以这里暂时不写。
        startProcessBtn.onClick.AddListener(StartProcess);              
        reStartProcess.onClick.AddListener(ReStartProcess);
    }
    /// <summary>
    /// 重新开始流程
    /// </summary>
    private void ReStartProcess()
    {
        CoverListMessage.ins.Show("温馨提示", "是否重新开始回放流程?", "重新回放流程");
    }
    /// <summary>
    /// 重新播放回放流程
    /// </summary>
    public void RestartProcessResult()
    {
        ReplayManager.Instance.replaySpeed = 1;
        ReplayManager.Instance.isFinish = false;
        speedText.text = "回放速度: 1X";
        Time.timeScale = 1;
        //先把之前uimanager里面的数据全部删除
        ReplayManager.Instance.ClearData();
        //重新给存储的数据赋值,然后开始重新回放
        Send("GetRePlayData", LoginManager.instance.replayAcc, NetworkManager.instance.taskName, LoginManager.instance.replayNumber, false);//在这里得到具体哪一次的回放
    }
    private void StartProcess()
    {
        ReplayManager.Instance.StartProcess();       
    }
    //[Rpc]
    public void GetRePlayDataResult(ReplayData data)
    {
        ReplayManager.Instance.data = data;

        Debug.Log("重新得到文件成功");
        transform.SetAsLastSibling();
        ReplayManager.Instance.GetData(ReplayManager.Instance.data);
        UnityEngine.SceneManagement.Scene scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
        timer = 0;
        totalTime = FormatNumberDateTime(((int)data.totalTimer).ToString());
        totalTimeText.text = string.Format("{0:D2}:{1:D2}", 0, 0) + "/" + totalTime;        
        //开始重新执行
        StartProcess();
    }

    /// <summary>
    /// 秒转换成时分秒(分的)
    /// </summary>
    /// <param name="secondTime"></param>
    /// <returns></returns>
    public string FormatNumberDateTime(string secondTime)
    {
        if (string.IsNullOrEmpty(secondTime))
        {
            return "";
        }
        else
        {
            long mss = long.Parse(secondTime);

            string DateTimes = null;
            long days = mss / (60 * 60 * 24);
            long hours = (mss % (60 * 60 * 24)) / (60 * 60);
            long minutes = (mss % (60 * 60)) / 60;
            long seconds = mss % 60;

            if (minutes > 0)
            {
                DateTimes = minutes + ":" + seconds;
            }
            else
            {
                DateTimes = "00:" + seconds;
            }
            return DateTimes;
        }
    }
    }

接下来是通用单例类,如果项目中有单例类的话就不用写这个类了。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// 脚本单例类
/// </summary>
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    //public static T Instance { get; private set; }

    //private void Awake()
    //{
    //    Instance = this as T;
    //}

    //何时何地都可以正确访问Instance?
    //按需加载

    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                //instance = this as T;
                instance = FindObjectOfType<T>();
                //如果在场景中没有找到该对象
                if (instance == null)
                {
                    //创建脚本对象,立即执行Awake,为instance赋值。
                    new GameObject("Singleton of " + typeof(T)).AddComponent<T>();
                }
                else
                {
                    instance.Initialize();
                }
            }
            return instance;
        }
    }
    public static T I
    {
        get { return Instance; }
    }
    protected virtual void Initialize() { }

    /*
           如果自行附加到物体中,希望instance属性可以在Awake赋值。
           情景:
           1. 如果单例类自行附加到游戏对象中。
               -- 客户端代码在Awake中访问Instance
               -- 客户端代码在Awake以后访问Instance

           2. 如果单例类没有附加。

     */
    protected virtual void Awake()
    {
        if (instance == null)
        {
            instance = this as T;
            Initialize();
        }
    }

    /*
     如何使用脚本单例类:
     1. 定义管理类,继承单例类,传递管理类类型。
     2. 重写Init方法进行初始化。
     **********************************
     3. 何时何地都可以通过以下代码访问管理类成员
         管理类.Instance.成员 
     */
}

接下来就是保存的数据类了

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class ReplayData
{


    public ReplayData()
    {
        buttonDic = new Dictionary<float, string>();
        toggleDic = new Dictionary<float, Dictionary<string, bool>>();
        dropDownDic = new Dictionary<float, Dictionary<string, int>>();
        inputFieldDic = new Dictionary<float, Dictionary<string, string>>();

        WoriginPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        WendPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        AoriginPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        AendPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        SoriginPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        SendPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        DoriginPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        DendPlayerTimeAndSpeedDic = new Dictionary<float, float>();
        AplayerPosX = new Dictionary<float, float>();
        AplayerPosY = new Dictionary<float, float>();
        AplayerPosZ = new Dictionary<float, float>();

        WplayerPosX = new Dictionary<float, float>();
        WplayerPosY = new Dictionary<float, float>();
        WplayerPosZ = new Dictionary<float, float>();
        SplayerPosX = new Dictionary<float, float>();
        SplayerPosY = new Dictionary<float, float>();
        SplayerPosZ = new Dictionary<float, float>();

        DplayerPosX = new Dictionary<float, float>();
        DplayerPosY = new Dictionary<float, float>();
        DplayerPosZ = new Dictionary<float, float>();

        playerDownRotX = new Dictionary<float, float>();
        playerDownRotY = new Dictionary<float, float>();
        playerDownRotZ = new Dictionary<float, float>();
        playerDownRotW = new Dictionary<float, float>();
        playerUpRotX = new Dictionary<float, float>();
        playerUpRotY = new Dictionary<float, float>();
        playerUpRotZ = new Dictionary<float, float>();
        playerUpRotW = new Dictionary<float, float>();


    }

    public float totalTimer = 0;
    public Dictionary<float, string> buttonDic;//时间、按钮名称
    public Dictionary<float, Dictionary<string, bool>> toggleDic;//时间、toggle名称、按钮的bool值
    public Dictionary<float, Dictionary<string, int>> dropDownDic;//时间、DropDown名称、DropDown的index值
    public Dictionary<float, Dictionary<string, string>> inputFieldDic;//时间、input的名字,input里面的内容

    public Dictionary<float, float> WoriginPlayerTimeAndSpeedDic;//按下W键位的时间、速度
    public Dictionary<float, float> WendPlayerTimeAndSpeedDic; //松开W键位的时间、速度

    public Dictionary<float, float> AoriginPlayerTimeAndSpeedDic;//按下A键位的时间、速度
    public Dictionary<float, float> AendPlayerTimeAndSpeedDic; //松开A键位的时间、速度

    public Dictionary<float, float> SoriginPlayerTimeAndSpeedDic;//按下S键位的时间、速度
    public Dictionary<float, float> SendPlayerTimeAndSpeedDic; //松开S键位的时间、速度

    public Dictionary<float, float> DoriginPlayerTimeAndSpeedDic;//按下D键位的时间、速度
    public Dictionary<float, float> DendPlayerTimeAndSpeedDic; //松开D键位的时间、速度



    public Dictionary<float, float> AplayerPosX;//按下A键位时当前时间、当前玩家位置X坐标
    public Dictionary<float, float> AplayerPosY;//按下A键位时当前时间、当前玩家位置Y坐标
    public Dictionary<float, float> AplayerPosZ;


    public Dictionary<float, float> WplayerPosX;//当前时间,当前玩家位置X坐标
    public Dictionary<float, float> WplayerPosY;//当前时间、当前玩家位置Y坐标
    public Dictionary<float, float> WplayerPosZ;


    public Dictionary<float, float> SplayerPosX;//当前时间、当前玩家位置X坐标
    public Dictionary<float, float> SplayerPosY;//当前时间、当前玩家位置Y坐标
    public Dictionary<float, float> SplayerPosZ;


    public Dictionary<float, float> DplayerPosX;//当前时间、当前玩家位置X坐标
    public Dictionary<float, float> DplayerPosY;//当前时间、当前玩家位置Y坐标
    public Dictionary<float, float> DplayerPosZ;



    public Dictionary<float, float> playerDownRotX;//当前时间、当前玩家旋转X坐标
    public Dictionary<float, float> playerDownRotY;
    public Dictionary<float, float> playerDownRotZ;
    public Dictionary<float, float> playerDownRotW;


    public Dictionary<float, float> playerUpRotX;//当前时间、当前玩家旋转X坐标
    public Dictionary<float, float> playerUpRotY;
    public Dictionary<float, float> playerUpRotZ;
    public Dictionary<float, float> playerUpRotW;
}

在程序中按下UI(比如按钮、toggle、在InputField)时,将此时按下的时间记录下来,保存到程序中。例如在按下按钮、Toggle、InputField触发事件时,同时也将数据进行记录。

//按下按钮
 if (!ReplayManager.Instance.rePlay)
                ReplayManager.Instance.data.buttonDic.Add(ReplayManager.Instance.timer, submitButton.name);
//按下Toggle开关
 if (!ReplayManager.Instance.rePlay)
        {
             ReplayManager.Instance.data.toggleDic.Add(ReplayManager.Instance.timer, new Dictionary<string, bool>());
             ReplayManager.Instance.data.toggleDic[ReplayManager.Instance.timer].Add(item.parent.name + item.GetComponent<Toggle>().name, isOn);
        }              
 //在InputField中输入文字
  if (!ReplayManager.Instance.rePlay)
            {
                ReplayManager.Instance.data.inputFieldDic.Add(ReplayManager.Instance.timer, new Dictionary<string, string>());
                ReplayManager.Instance.data.inputFieldDic[ReplayManager.Instance.timer].Add(input.gameObject.name, content);
            }
                

在最后保存的时候,将ReplayData类发送给服务器,将ReplayData中的数据转化为二进制文件进行保存,保存的代码为

  /// <summary>
        /// 保存回放记录
        /// </summary>
        /// <param name="playerAcc">玩家用户名</param>
        /// <param name="taskName">任务名称</param>
        /// <param name="data">数据类</param>
        [Rpc]
        public void SetRePlayData(string playerAcc, string taskName, ReplayData data)
        {
            //首先设置数据库信息
            db = new SQLServerDatabase(0);
            db.UpdateValues("Student_TaskPlan",
                new string[] { "hasReplay" },
                new string[] { "true" },
                "playerAcc", playerAcc, "TaskName", taskName);

            int numberOfReplayTime = serverManager.player.numberOfTask + 1;
            string rootPath = Environment.CurrentDirectory.ToString();
            string path = rootPath + "\\" + "ReplayFile" + "\\" + playerAcc;//通过人物名生成第一个文件夹
            string path2 = path + "\\" + taskName;
            string path3 = path2 + "\\" + "第" + numberOfReplayTime.ToString() + "次回放.rep";//保存第几次考核的回放
            DirectoryInfo d = Directory.CreateDirectory(path);//创建根目录  返回值是一个文件夹
            DirectoryInfo d2 = Directory.CreateDirectory(path2);
            File.Create(path3).Close();
            ReplayData replayData = new ReplayData();
            replayData = data;
            BinaryFormatter bf = new BinaryFormatter();
            using (FileStream fs = File.Create(path3))
            {
                bf.Serialize(fs, replayData);
            }
//发送给玩家,告诉玩家回放已经保存成功
            serverManager.Send(serverManager.player, "SetRePlayDataResult", "保存回放成功");
        }

//在这里是读取之前保存的回放数据

///用户名、任务名称、想要查看第几次回放 
public void GetRePlayData(string playerAcc, string taskName, string numberOfTask, bool isFirst)
        {
            string rootPath = Environment.CurrentDirectory.ToString();
            string path = rootPath + "\\" + "ReplayFile" + "\\" + playerAcc + "\\" + taskName + "\\" + numberOfTask + ".rep";
            BinaryFormatter bf = new BinaryFormatter();
            ReplayData data = new ReplayData();
            using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
            {
            //创建data类
                data = bf.Deserialize(fs) as ReplayData;
            }
            if (isFirst)
                serverManager.SendRT(serverManager.player, "GetFirstRePlayDataResult", data);
            else
            {
                serverManager.SendRT(serverManager.player, "GetRePlayDataResult", data);
            }
        }

总结

写到这里差不多就将回放功能的大致框架完成了,中间可能有些乱,但是写这篇文章的初衷就是给自己以后看的,大致内容还是比较清楚的。如果有看到这篇文章后想要了解更多、或者有什么不懂的地方的朋友可以加我一起讨论。附带Q:770187276

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值