【Unity】通過實時記錄模擬時間倒退效果回放

有一些遊戲提供了回退的功能,那麼在遊戲開發中如何實現時間倒退這個效果呢,相信會有很多人想知道,爲此下面就給大家介紹下實現時間倒退效果的方法,一起來看看吧。
  
  一個簡單的思路就是用Stack來記錄物體的Position和Rotation,當需要時間回退的時候就Pop出來,賦值到物體上。不過爲了可以進行拓展,比如只能回退到某段時間內的,而不是一下子回退到最開始的地方,我們需要剔除太久之前的信息。如下圖:
Unity如何實現時間倒退效果  
  因此我選擇使用List而不是Stack。
  
  代碼(完整代碼在最下面)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Pos
Vector3 pos = this.transform.position;
floathorizontal = Input.GetAxis("Horizontal");
floatvertical = Input.GetAxis("Vertical");
 
if(Mathf.Abs(horizontal) > 0.0001f) //左右移動
{
    pos.x += Time.deltaTime * horizontal * Speed;
}
if(Mathf.Abs(vertical) > 0.0001f) //上下移動
{
    pos.y += Time.deltaTime * vertical * Speed;
}
this.transform.position = pos;
 
HistoryPos.Add(pos);
  
  這裏HistoryPos就是我們用來存儲歷史位置的List,我們每幀都存儲物體的位置。
  
  當我們需要時間回退時,可以每幀調用下面的代碼:
1
2
3
4
5
6
if(HistoryPos.Count > 0)
{
    intindex = HistoryPos.Count - 1;
    this.transform.position = HistoryPos[index];
    HistoryPos.RemoveAt(index);
}
  
  這就是每次取出最後的位置(即最新的),賦值到物體上
  
  當我們需要限制時間回退的時間跨度,可以在HistoryPos.Add後加上下面這些代碼:
1
2
3
4
5
6
HistoryPos.Add(pos);
 
if(ShouldLimit && HistoryPos.Count > Limit)
{
    HistoryPos.RemoveAt(0);
}
  
  因爲旋轉是雷同的,因此就不貼代碼出來了。
  
  改進
  
  1.這裏我們是每幀都記錄信息,這樣List的大小很容易暴走,因此我們可以每隔一段時間來記錄,然後要時間回退的時候就進行插值。
  
  2.通常我們的物體都帶有動畫,這時倒播動畫就行。如果在時間回退過程中存在多個動畫,我們就需要自己設計數據結構來保存某個時刻對應的動畫和動畫狀態。
  
  完整代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
 
///
/// 就是利用Stack的原理來獲取歷史位置
/// 如果同時有動畫,把動畫倒放就是
///
publicclass TBPlayer : MonoBehaviour {
    publicint Speed = 3;
    publicint RotateSpeed = 100;
    publicbool ShouldLimit = false;
    publicint Limit = 100; //可以存放的座標上限
 
    privateList HistoryPos;
    privateList HistoryRot;
    privatebool _IsTimeBack = false;
 
    voidStart () {
        HistoryPos = newList();
        HistoryRot = newList();
    }
 
    voidUpdate () {
        if(_IsTimeBack)
            TimeBack();
        else
            ControlPos();
    }
 
    voidControlPos()
    {
        //Pos
        Vector3 pos = this.transform.position;
        floathorizontal = Input.GetAxis("Horizontal");
        floatvertical = Input.GetAxis("Vertical");
 
        if(Mathf.Abs(horizontal) > 0.0001f) //左右移動
        {
            pos.x += Time.deltaTime * horizontal * Speed;
        }
        if(Mathf.Abs(vertical) > 0.0001f) //上下移動
        {
            pos.y += Time.deltaTime * vertical * Speed;
        }
        this.transform.position = pos;
 
        HistoryPos.Add(pos);
 
        //Rotation
        Quaternion rot = this.transform.rotation;
        Vector3 rotv = rot.eulerAngles;
        floatrotate = Input.GetAxis("Fire1");
 
        if(Mathf.Abs(rotate) > 0.0001f)
        {
            rotv.z += Time.deltaTime * rotate * RotateSpeed;
        }
        rot = Quaternion.Euler(rotv);
        this.transform.rotation = rot;
 
        HistoryRot.Add(rot);
 
        if(ShouldLimit && HistoryPos.Count > Limit)
        {
            HistoryPos.RemoveAt(0);
            HistoryRot.RemoveAt(0);
        }
    }
 
    voidTimeBack()
    {
        if(HistoryPos.Count > 0)
        {
            intindex = HistoryPos.Count - 1;
            this.transform.position = HistoryPos[index];
            HistoryPos.RemoveAt(index);
        }
        if(HistoryRot.Count > 0)
        {
            intindex = HistoryRot.Count - 1;
            this.transform.rotation = HistoryRot[index];
            HistoryRot.RemoveAt(index);
        }
    }
 
    voidOnGUI()
    {
        if(GUILayout.Button("時間倒流"))
        {
            _IsTimeBack = true;
        }
        if(GUILayout.Button("Reset"))
        {
            HistoryRot.Clear();
            HistoryPos.Clear();
            _IsTimeBack = false;
        }
    }
}
  
  效果
Unity如何實現時間倒退效果
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章