Unity3D实现回放的功能(记录操作数)
发表于2017-09-21
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回放的功能如果有更好的形式,欢迎指教~