Unity3D实现回放的功能(记录操作数)

发表于2017-09-21
评论1 7.7k浏览
Unity3D实现类似录制回放的功能:

运行的时候开始记录,此时可以在编辑场景中拖动物体移动,然后移至game场景按下E键结束录制,在按下R键播放之前的操作。

项目做的比较简单,只是提供一个思路~



1.首先创建一个类用于储存想要记录的信息,在类中写下方法可以将这些信息转换为字符串,便于在后面执行记录,将信息以字符串的形式储存在Txt文件中,同样的在这个类中写下把字符串分割为记录的信息,本例为位置信息,所以分割三个数值分别赋予Vector3的X,Y,Z。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
namespace LReplay
{
    public class ReplayObject
    {
        //记录位置
        public Vector3 vectorPos;
        public int timePos;
        //时间点位置信息变为字符串
        public static string TimePositionToString(int timePos,Transform target) {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0};", timePos);
            sb.AppendFormat("{0},{1},{2}|",
                target.transform.localPosition.x,
                target.transform.localPosition.y,
                target.transform.localPosition.z);
            //Debug.Log(sb.ToString());
            return sb.ToString();
        }
        //分割字符串根据“|”分割
        void StringToPosition(string tarString) {
            string[] Contans = tarString.Split('|');
            this.StringToPositionXYZ(Contans[0]);
        }
        //分割储存位置的字符串根据“,”分割
        void StringToPositionXYZ(string tarString) {
            if (string.IsNullOrEmpty(tarString))
                return;
            string[] Pos = tarString.Split(',');
            this.vectorPos.x = float.Parse(Pos[0]);
            this.vectorPos.y = float.Parse(Pos[1]);
            this.vectorPos.z = float.Parse(Pos[2]);
        }
        //分割字符串“;”得到时间及位置字符串
        public void  GetTimeAndPosition(string Str)
        {
            string[] TimeAndPos = Str.Split(';');
            timePos = int.Parse(TimeAndPos[0]);
            this.StringToPosition(TimeAndPos[1]);
        }
    }
}
2.编辑记录位置信息的脚本
脚本在固定的间隔去记录物体的位置,如果物体的位置没有发生改变不记录到Txt文件中,如果改变了则记录到Txt文件中
注:这里面写了一个json的类测试json的记录功能,注意使用json需要导入json的插件,这里只需要使用TXT文件去记录位置信息即可
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using System.IO;
using Newtonsoft.Json;
namespace LReplay
{
    public class MyJson
    {
        public string myString = "lala";
        public int scoure = 3;
        public float scoures = 3.0f;
    }
    public class TestJson : MonoBehaviour
    {
        //时间点
        public int timePos;
        //记录的目标
        public GameObject target;
        //开始记录的时间
        public float startRecordTime;
        //txt路径名称
        private string txtFileName;
        //Json路径名称
        private string jsonFileName;
        //记录间隔
        private float recordInterval;
        //判断位置是否改变
        protected Vector3 cachePosition = new Vector3(1000.0f, 0f, 0f);
        //流文件
        private StreamWriter streamWriter;
        private MyJson myJson;
        private ReplayObject myReplayObject;
        private void Awake()
        {
            myJson = new MyJson();
        }
        private void Start()
        {
            txtFileName = Application.dataPath   "/TextFile"   "/File.txt";
            jsonFileName = Application.dataPath   "/TextFile"   "/File.json";
            CreatTxtAndJson();
            //timePos = Time.realtimeSinceStartup;
            recordInterval = 0.033f;
            startRecordTime = 2.0f;
            StartRecord();
        }
        //生成文件
        void CreatTxtAndJson()
        {
            if (!File.Exists(txtFileName))
            {
                streamWriter = File.CreateText(txtFileName);
            }
            else
            {
                Debug.Log("Txt Is Exist!");
            }
            if (!File.Exists(jsonFileName))
            {
                File.Create(jsonFileName);
            }
            else
            {
                Debug.Log("Json Is Exist!");
            }
        }
        //开始记录
        void StartRecord()
        {
            FileInfo fileInfo = new FileInfo(txtFileName);
            streamWriter = fileInfo.CreateText();
            string jsonStr = JsonConvert.SerializeObject(this.myJson, Formatting.None, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });
            FileInfo fileInfo2 = new FileInfo(jsonFileName);
            using (StreamWriter sw = fileInfo2.CreateText())
            {
                sw.Write(jsonStr);
            }
        }
        //写入文件
        void WriteData(string saveData)
        {
            streamWriter.WriteLine(saveData);
        }
        //结束写入
        void Finished()
        {
            streamWriter.Flush();
            streamWriter.Close();
        }
        private void Update()
        {
            //timePos = Time.realtimeSinceStartup*100;
            string curData =string.Empty;
            if (Time.realtimeSinceStartup - startRecordTime >= recordInterval)
            {
                timePos  ;
                curData = ReplayObject.TimePositionToString(timePos, target.transform);
                if (!cachePosition.Equals(target.transform.localPosition))
                {
                    WriteData(curData);
                    this.cachePosition = this.target.transform.localPosition;
                    //Debug.Log("1111111111");
                }
                this.startRecordTime = Time.realtimeSinceStartup;
            }
            //按下E键停止记录
            if (Input.GetKeyDown(KeyCode.E))
            {
                Finished();
            }
        }
    }
}
txt文件记录的内容

3.编辑回放脚本
编辑回放脚本,读取之前记录的位置信息放入队列,然后动态加载这些位置数据
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
namespace LReplay
{
    public class ReplayScript : MonoBehaviour
    {
        public int timePos=0;
        public float startTimePos=0;
        public Transform target;
        public float replayInterval;
        public bool isReplay = false;
        ReplayObject replayEntity;
        //使用队列来动态加载位置数据
        protected Queue<ReplayObject> readyToReplayData;
        private void Start()
        {
            readyToReplayData = new Queue<ReplayObject>();
            readyToReplayData.Clear();
            replayInterval = 0.02f;
        }
        private void Update()
        {
            //按下Q键回放之前的操作
            if (Input.GetKeyDown(KeyCode.R))
            {
                startTimePos = Time.realtimeSinceStartup ;
                StartCoroutine(LoadReolayDataFromFile());
                timePos = 0;
                isReplay = true;
            }
            if (isReplay) {
                if (Time.realtimeSinceStartup - this.startTimePos >= replayInterval) {
                    timePos  ;
                    startTimePos = Time.realtimeSinceStartup;
                    ReplayObject curState = this.readyToReplayData.Peek();
                    if (curState.timePos == timePos) {
                        target.transform.position = curState.vectorPos;
                        curState = this.readyToReplayData.Dequeue();
                    }
                }
            }
        }
        //读取记录位置文件的信息
        IEnumerator LoadReolayDataFromFile()
        {
            string fileName = Application.dataPath   "/TextFile"   "/File.txt";
            FileInfo fileInfo = new FileInfo(fileName);
            string lineData = string.Empty;
            int dataCount = 0;
            if (fileInfo.Exists)
            {
                using (StreamReader sr = fileInfo.OpenText())
                {
                    while ((lineData = sr.ReadLine()) != null)
                    {
                        dataCount  ;
                        replayEntity = new ReplayObject();
                        replayEntity.GetTimeAndPosition(lineData);
                        readyToReplayData.Enqueue(replayEntity);
                    }
                }
            }
            yield return null;
        }
    }
}

工程文件已上传到百度云:http://pan.baidu.com/s/1slVwr85 密码:fsu8

关于Unity回放的功能如果有更好的形式,欢迎指教~

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签:

0个评论