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回放的功能如果有更好的形式,欢迎指教~
