diff options
Diffstat (limited to 'JamHelper/Assets/Scripts/Smooth-Motion-in-Unity')
9 files changed, 253 insertions, 0 deletions
diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs new file mode 100644 index 0000000..efb96f3 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs @@ -0,0 +1,58 @@ +using UnityEngine; + +[DisallowMultipleComponent] +[DefaultExecutionOrder(ORDER_EXECUTION)] +public class InterpolationFactorController : MonoBehaviour +{ + public const int ORDER_EXECUTION = -1000; + + private static InterpolationFactorController Instance; + private float[] _lastFixedUpdates = new float[2]; + private int _lastIndex; + + public static float Factor { get; private set; } + + private void Awake() + { + if (Instance) + { + Destroy(this); + Debug.LogWarning($"The '{typeof(InterpolationFactorController).Name}' is a singleton!"); + return; + } + + Instance = this; + Factor = 1; + } + + private void Start() + { + _lastFixedUpdates = new float[2] { Time.fixedTime, Time.fixedTime }; + _lastIndex = 0; + } + + private void FixedUpdate() + { + _lastIndex = NextIndex(); + _lastFixedUpdates[_lastIndex] = Time.fixedTime; + } + + private void Update() + { + float lastTime = _lastFixedUpdates[_lastIndex]; + float prevTime = _lastFixedUpdates[NextIndex()]; + + if (lastTime == prevTime) + { + Factor = 1; + return; + } + + Factor = (Time.time - lastTime) / (lastTime - prevTime); + } + + private int NextIndex() + { + return (_lastIndex == 0) ? 1 : 0; + } +} diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs.meta b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs.meta new file mode 100644 index 0000000..5ccc518 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationFactorController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e46e87749463bf14c853d26c9f2d94b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs new file mode 100644 index 0000000..9a83fe0 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs @@ -0,0 +1,117 @@ +using System.Collections; +using UnityEngine; + +[DisallowMultipleComponent] +[DefaultExecutionOrder(ORDER_EXECUTION)] +public class InterpolationObjectController : MonoBehaviour +{ + public 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]; + transform.localPosition = latest.position; + transform.localScale = latest.scale; + transform.localRotation = latest.rotation; + } + + private void SaveActualTransform() + { + _index = NextIndex(); + _transforms[_index] = CurrentTransformData(); + } + + private void SetInterpolatedTransform() + { + var prev = _transforms[NextIndex()]; + float factor = InterpolationFactorController.Factor; + transform.localPosition = Vector3.Lerp(prev.position, transform.localPosition, factor); + transform.localRotation = Quaternion.Slerp(prev.rotation, transform.localRotation, factor); + 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 +} diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs.meta b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs.meta new file mode 100644 index 0000000..3713b90 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/InterpolationObjectController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b67d250d8c3c3444696fd7025a189cb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md new file mode 100644 index 0000000..016072b --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md @@ -0,0 +1,12 @@ +# Smooth Motion in Unity (refactored) + +This is an improved (refactored) version of the code from the ["Timesteps and Achieving Smooth Motion in Unity"](https://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8?utm_source=youtube&utm_type=SMVideo) article. + +Now, there are only 2 components instead of original 3: + +1. [`InterpolationFactorController`](https://github.com/DevelAx/Smooth-Motion-in-Unity/blob/master/InterpolationFactorController.cs) a singleton scene component (the original name was `InterpolationController`) that calculates the current *interpolation factor*. +2. [`InterpolationObjectController`](https://github.com/DevelAx/Smooth-Motion-in-Unity/blob/master/InterpolationObjectController.cs) a component for a moving object (the original name was `InterpolatedTransform`) which calculates the current interpolation for the object in the `Update()` method before it's being rendered and then restores its original `transform` values for the next `FixedUpdate()` call. +3. The `InterpolatedTransformUpdater` component was removed as unnecessary. + +## Remarks +For these scripts to work correctly the user's script must change the object's `transform` only in the `FixedUpdate()` method. When teleporting the object the user should call the (`InterpolationObjectController`).`ResetTransforms()` method after it. diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md.meta b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md.meta new file mode 100644 index 0000000..51d1cc8 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 21e83c3a42dfa0a41a26dd8be5efb875 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests.meta b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests.meta new file mode 100644 index 0000000..50f7279 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74360e905b7961943baf642bbadbd795 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs new file mode 100644 index 0000000..3bf706a --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +/// <summary> +/// Use this component with a game object for demonstration purposes. +/// </summary> +[DisallowMultipleComponent] +[RequireComponent(typeof(InterpolationObjectController))] +public class TestMotion : MonoBehaviour +{ + [SerializeField] + private float _speed = 2f; + + private void FixedUpdate() + { + transform.position += Vector3.right * _speed * Time.fixedDeltaTime; + transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + _speed * 30 * Time.fixedDeltaTime, transform.rotation.eulerAngles.z); + } +} diff --git a/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs.meta b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs.meta new file mode 100644 index 0000000..ed36b36 --- /dev/null +++ b/JamHelper/Assets/Scripts/Smooth-Motion-in-Unity/Tests/TestMotion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d5926e8356360240bdac050edba52a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |