Unity 回放功能

记录一个回放脚本,改脚本通过记录物体位置信息进行回放

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
 
public class RecordStateList
{
    public Dictionary<float,Vector3> pos = new Dictionary<float, Vector3>();
    public Dictionary<float, Quaternion> rot = new Dictionary<float, Quaternion>();
    public Dictionary<float, Vector3> scale = new Dictionary<float, Vector3>();
    public bool isDispose = false;
    private GameObject go;
    private float startRecordTime;
    private float startPlayTime;
    private float playSpd = 1;
    private bool stoped = false;
    private Action endCb = null;
    private Vector3 lastPos;
    private Quaternion lastRot;
    private Vector3 lastScale;
 
    public RecordStateList(GameObject g)
    {
        go = g;
    }
 
    public void Start()
    {
 
        if (go != null)
        {
            lastPos = go.transform.position;
            lastRot = go.transform.rotation;
            lastScale = go.transform.localScale;
        }
        startRecordTime = Time.time;
        Record();
        SupportBehavior.inst.m_onFixedUpdate.Add(Record);
    }
 
    public void Record()
    {
        if (go == null)
        {
            Stop();
            isDispose = true;
        }
        else
        {
            pos.Add(Time.time - startRecordTime, go.transform.position);
            rot.Add(Time.time - startRecordTime, go.transform.rotation);
            scale.Add(Time.time - startRecordTime, go.transform.localScale);
        }
    }
 
    public void Stop()
    {
        stoped = true;
        SupportBehavior.inst.m_onFixedUpdate.Remove(Record);
    }
 
    public void Play(Action playEndCb,float spd = 1f)
    {
        if (!stoped)
        {
            Stop();
        }
        endCb = playEndCb;
        playSpd = spd;
        startPlayTime = Time.unscaledTime;
        PlayPreframe();
        SupportBehavior.inst.m_onUpdate.Add(PlayPreframe);
    }
 
    public void PlayPreframe()
    {
        try
        {
            if (!isDispose)
            {
                float sec = playSpd * (Time.unscaledTime - startPlayTime);
                bool hasCb = false;
                Action cb = () =>
                {
                    if (!hasCb)
                    {
                        hasCb = true;
                        SupportBehavior.inst.m_onUpdate.Remove(PlayPreframe);
                        endCb();
                        return;
                    }
                };
                if (go != null)
                {
                    go.transform.position = GetPosBetween(sec, pos, () =>
                    {
                        cb();
                    });
                    go.transform.rotation = GetRotBetween(sec, rot, () =>
                    {
                        cb();
                    });
                    go.transform.localScale = GetPosBetween(sec, scale, () =>
                    {
                        cb();
                    });
                }
                else
                {
                    cb();
                }
            }else
            {
                endCb();
            }
            
        }
        catch(Exception e)
        {
            Debug.LogError("!Error!" + e.ToString());
        }
    }
 
    public void Reset()
    {
        if (go != null)
        {
            go.transform.position = lastPos;
            go.transform.rotation = lastRot;
            go.transform.localScale = lastScale;
        }
    }
 
    public void Dispose()
    {
        SupportBehavior.inst.m_onUpdate.Remove(PlayPreframe);
        pos.Clear();
        rot.Clear();
        scale.Clear();
        isDispose = true;
    }
 
    private Vector3 GetPosBetween(float t,Dictionary<float, Vector3> dic,Action cb)
    {
        List<float> times = new List<float>(dic.Keys);
        for(int i = 0; i < times.Count; i++)
        {
            if (i+1 < times.Count)
            {
                if (t == times[i])
                {
                    return dic[times[i]];
                }
                if (times[i] < t && times[i + 1] > t)
                {
                    float k = times[i];
                    float nk = times[i + 1];
                    Vector3 min = dic[k];
                    Vector3 max = dic[nk];
                    float percent = (t - k) / (nk - k);
                    return min + ((max - min) * percent);
                }
                else if (t <= times[0])
                {
                    return dic[times[0]];
                }
            }
            else
            {
                //Vector3 p = dic[times[times.Count - 1]];
                cb();
                return lastPos;
            }
        }
        return lastPos;//dic[times[times.Count - 1]];
    }
 
    private Quaternion GetRotBetween(float t,Dictionary<float,Quaternion>dic,Action cb)
    {
        List<float> times = new List<float>(dic.Keys);
        for (int i = 0; i < times.Count; i++)
        {
            if (i + 1 < times.Count)
            {
                if (t == times[i])
                {
                    return dic[times[i]];
                }
                if (times[i] < t && times[i + 1] > t)
                {
                    float k = times[i];
                    float nk = times[i + 1];
                    Quaternion min = dic[k];
                    Quaternion max = dic[nk];
                    float percent = (t - k) / (nk - k);
                    return Quaternion.Lerp(min,max, percent);
                }
                else if (t <= times[0])
                {
                    return dic[times[0]];
                }
            }
            else
            {
                //Quaternion r = dic[times[times.Count - 1]];
                cb();
                return lastRot;
            }
        }
        return lastRot;
    }
}
 
public class Recorder {
    
    private Dictionary<GameObject, RecordStateList> records = new Dictionary<GameObject, RecordStateList>();
 
    private GameObject root;
 
    private static List<Recorder> allRecords = new List<Recorder>();
 
	public Recorder(GameObject go)
    {
        root = go;
        Clear();
    }
 
    public void Clear()
    {
        records.Clear();
        root.IterateGameObject(g =>
        {
            records.Add(g, new RecordStateList(g));
        });
    }
 
    public void StartRecord()
    {
        Clear();
        foreach (KeyValuePair<GameObject,RecordStateList>pair in records)
        {
            pair.Value.Start();
        }
    }
 
    public void Stop()
    {
        foreach (KeyValuePair<GameObject, RecordStateList> pair in records)
        {
            pair.Value.Stop();
        }
    }
 
    public void Play(float spd,Action cb)
    {
        int cbNum = 0;
        List<GameObject> gos = new List<GameObject>(records.Keys);
        for(int i = 0; i < gos.Count; i++)
        {
            if (gos[i] == null)
            {
                records.Remove(gos[i]);
            }
        }
        Behaviour[] comps = root.GetComponents<Behaviour>();
        for(int i = 0; i < comps.Length; i++)
        {
            comps[i].enabled = false;
        }
        foreach (KeyValuePair<GameObject, RecordStateList> pair in records)
        {
            pair.Value.Play(() => {
                cbNum++;
                if (cbNum >= records.Count)
                {
                    for (int i = 0; i < comps.Length; i++)
                    {
                        comps[i].enabled = true;
                    }
                    foreach (KeyValuePair<GameObject, RecordStateList> p in records)
                    {
                        p.Value.Reset();
                        p.Value.Dispose();
                    }
                    cb();
                }
            }, spd);
        }
    }
 
    public static void Record(List<GameObject> objs)
    {
        allRecords.Clear();
        for (int i = 0; i < objs.Count; i++)
        {
            allRecords.Add(new Recorder(objs[i]));
            allRecords[i].StartRecord();
        }
    }
 
    public static void StopRecord()
    {
        for (int i = 0; i < allRecords.Count; i++)
        {
            allRecords[i].Stop();
        }
    }
 
    public static void ReplayRecord(float spd,Action cb)
    {
        int id = 0;
        for(int i = 0; i < allRecords.Count; i++)
        {
            allRecords[i].Play(spd,()=>
            {
                id++;
                if (id == allRecords.Count)
                {
                    cb();
                    allRecords.Clear();
                }
            });
        }
    }
}

接下来是演示如何使用的案例脚本:

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
 
 
public class playerTest : MonoBehaviour {
 
    public Animator anim;
    private Vector3 targetPos;
    //private Recorder record;
 
    private bool isReplay = false;
    void Awake()
    {
        anim = GetComponent<Animator>();
        //record = new Recorder(gameObject);
    }
 
    void Start()
    {
 
    }
 
    void Update()
    {
 
    }
 
    private void OnGUI()
    {
        if (GUILayout.Button("Record"))
        {
            //record.StartRecord();
            Recorder.Record(new List<GameObject>() { gameObject });
        }
        if (GUILayout.Button("Play"))
        {
            isReplay = true;
            //anim.enabled = false;
            //record.Play(0.1f,()=> { });
            Recorder.ReplayRecord(0.5f, () =>
            {
                Debug.Log("All OK!!!");
            });
        }
        if (GUILayout.Button("Run1"))
        {
            anim.SetTrigger("Run01");
            targetPos = new Vector3(5f, 0, 3f);
        }
        if (GUILayout.Button("Run2"))
        {
            anim.SetTrigger("Run02");
            targetPos = new Vector3(3f, 0, 6f);
        }
        if (!isReplay && Vector3.Distance(transform.position, targetPos) > 0.1f)
        {
            transform.LookAtXZ(targetPos);
            transform.position += (targetPos - transform.position).normalized * 4f * Time.deltaTime;
        }
    }
}

SupportBehavior工具是一个工具类,主要是延时功能。地址:https://blog.csdn.net/qq_32225289/article/details/84952406

原文地址:https://blog.csdn.net/qq_32225289/article/details/87986158

猜你喜欢

转载自blog.csdn.net/abc1090275833/article/details/88021495