aboutsummaryrefslogtreecommitdiff
path: root/JamHelper/Assets/JamUtils/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs
blob: 3b6c0decd5c5ba00d75cdbf899678a2f129b32da (plain)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Collections;
using UnityEngine;

[DisallowMultipleComponent]
[DefaultExecutionOrder(ORDER_EXECUTION)]
public class InterpolationObjectController : MonoBehaviour
{
    [Flags]
    public enum InterpolateType
    {
        None,
        Position = 1, 
        Rotation = 1 << 1,  
        Scale = 1 << 2, 
    }

    public InterpolateType type;

    private const int ORDER_EXECUTION = InterpolationFactorController.ORDER_EXECUTION - 1;

    private TransformData[] _transforms;
    private int _index;

    private void Awake()
    {
        StartCoroutine(WaitForEndOfFrame());
        StartCoroutine(WaitForFixedUpdate());
    }

    private void OnEnable()
    {
        ResetTransforms();
    }

    private void BeforeFixedUpdate()
    {
        // Restoring actual transform for the FixedUpdate() cal where it could be change by the user.
        RestoreActualTransform();
    }

    private void AfterFixedUpdate()
    {
        // Saving actual transform for being restored in the BeforeFixedUpdate() method.
        SaveActualTransform();
    }

    private void Update()
    {
        // Set interpolated transform for being rendered.
        SetInterpolatedTransform();
    }

    #region Helpers

    private void RestoreActualTransform()
    {
        var latest = _transforms[_index];

        if((type & InterpolateType.Position) != 0)
            transform.localPosition = latest.position;
        if ((type & InterpolateType.Scale) != 0)
            transform.localScale = latest.scale;
        if ((type & InterpolateType.Rotation) != 0)
            transform.localRotation = latest.rotation;
    }

    private void SaveActualTransform()
    {
        _index = NextIndex();
        _transforms[_index] = CurrentTransformData();
    }

    private void SetInterpolatedTransform()
    {
        var prev = _transforms[NextIndex()];
        float factor = InterpolationFactorController.Factor;
        if ((type & InterpolateType.Position) != 0)
            transform.localPosition = Vector3.Lerp(prev.position, transform.localPosition, factor);
        if ((type & InterpolateType.Rotation) != 0)
            transform.localRotation = Quaternion.Slerp(prev.rotation, transform.localRotation, factor);
        if ((type & InterpolateType.Scale) != 0)
            transform.localScale = Vector3.Lerp(prev.scale, transform.localScale, factor);
    }

    public void ResetTransforms()
    {
        _index = 0;
        var td = CurrentTransformData();
        _transforms = new TransformData[2] { td, td };
    }

    private TransformData CurrentTransformData()
    {
        return new TransformData(transform.localPosition, transform.localRotation, transform.localScale);
    }

    private int NextIndex()
    {
        return (_index == 0) ? 1 : 0;
    }

    private IEnumerator WaitForEndOfFrame()
    {
        while (true)
        {
            yield return new WaitForEndOfFrame();
            BeforeFixedUpdate();
        }
    }

    private IEnumerator WaitForFixedUpdate()
    {
        while (true)
        {
            yield return new WaitForFixedUpdate();
            AfterFixedUpdate();
        }
    }

    private struct TransformData
    {
        public Vector3 position;
        public Quaternion rotation;
        public Vector3 scale;

        public TransformData(Vector3 position, Quaternion rotation, Vector3 scale)
        {
            this.position = position;
            this.rotation = rotation;
            this.scale = scale;
        }
    }

    #endregion
}