From d7bea7bbf3ba08255e87e79f133a4aa9c70e6875 Mon Sep 17 00:00:00 2001 From: Adrian Paschkowski <git@wasdennnoch.me> Date: Thu, 8 Apr 2021 22:03:57 +0200 Subject: [PATCH] Add LayeredInterpolator, interpolate cam pos and not input Allows you to animate to a specific world position on request. --- Assets/Scenes/Forest.unity | 2 + Assets/Scripts/BaseCameraController.cs | 53 +++++++++----- Assets/Scripts/Box.cs | 2 + Assets/Scripts/Interpolator.cs | 16 ++--- Assets/Scripts/LayeredInterpolator.cs | 83 ++++++++++++++++++++++ Assets/Scripts/LayeredInterpolator.cs.meta | 11 +++ 6 files changed, 141 insertions(+), 26 deletions(-) create mode 100644 Assets/Scripts/LayeredInterpolator.cs create mode 100644 Assets/Scripts/LayeredInterpolator.cs.meta diff --git a/Assets/Scenes/Forest.unity b/Assets/Scenes/Forest.unity index 52721d6..80e03cb 100644 --- a/Assets/Scenes/Forest.unity +++ b/Assets/Scenes/Forest.unity @@ -440,6 +440,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 4471af6bb2e057546a362ad75c91f770, type: 3} m_Name: m_EditorClassIdentifier: + allowUserControl: 1 + inputVelocity: 2.5 moveSpeed: 10 edgeDetectionBoxInsets: {x: 0.1, y: 0.1} maxZoom: 5 diff --git a/Assets/Scripts/BaseCameraController.cs b/Assets/Scripts/BaseCameraController.cs index 745a8a9..efbc50b 100644 --- a/Assets/Scripts/BaseCameraController.cs +++ b/Assets/Scripts/BaseCameraController.cs @@ -8,6 +8,7 @@ public class BaseCameraController : MonoBehaviour [SerializeField] bool allowUserControl = true; [Header("Movement")] + [SerializeField] float inputVelocity = 2f; [SerializeField] float moveSpeed = 10f; [SerializeField] Vector2 edgeDetectionBoxInsets = new Vector2(0.1f, 0.1f); @@ -24,10 +25,10 @@ public class BaseCameraController : MonoBehaviour InsetCameraEdges mouseMovementEdges; bool waitForMouseOutsideEdges = false; - Interpolator zoomInterpolator; - Interpolator moveXInterpolator; - Interpolator moveYInterpolator; - Vector3 inputVector = Vector3.zero; + LayeredInterpolator zoomInterpolator; + LayeredInterpolator xPositionInterpolator; + LayeredInterpolator yPositionInterpolator; + Vector2 inputVector; float zoomRatio { get => camera.orthographicSize / maxZoom; @@ -43,6 +44,13 @@ public class BaseCameraController : MonoBehaviour this.allowUserControl = allowUserControl; } + public void AnimateToPosition(Vector3 worldPos, float zoom, float duration) + { + zoomInterpolator.PushInterpolator(new Interpolator(duration, camera.orthographicSize, zoom)); + xPositionInterpolator.PushInterpolator(new Interpolator(duration, transform.position.x, worldPos.x)); + yPositionInterpolator.PushInterpolator(new Interpolator(duration, transform.position.y, worldPos.y)); + } + void Awake() { camera = GetComponent<Camera>(); @@ -51,15 +59,22 @@ public class BaseCameraController : MonoBehaviour rigidbody = GetComponent<Rigidbody2D>(); mouseMovementEdges = new InsetCameraEdges(camera, edgeDetectionBoxInsets); - zoomInterpolator = new Interpolator(1 / zoomSpeed, camera.orthographicSize, camera.orthographicSize, minZoom, maxZoom); - moveXInterpolator = new Interpolator(1 / moveSpeed); - moveYInterpolator = new Interpolator(1 / moveSpeed); + zoomInterpolator = new LayeredInterpolator(new Interpolator(1 / zoomSpeed, camera.orthographicSize, camera.orthographicSize, minZoom, maxZoom)); + xPositionInterpolator = new LayeredInterpolator(new Interpolator(1 / moveSpeed, transform.position.x)); + yPositionInterpolator = new LayeredInterpolator(new Interpolator(1 / moveSpeed, transform.position.y)); UpdateColliderSize(); } void Update() { - var inputZoomDelta = allowUserControl ? Input.mouseScrollDelta.y * -zoomStepSize : 0; + if (Input.GetKeyDown(KeyCode.Z)) // TODO Remove evntually + { + var player = GameObject.FindGameObjectWithTag("Player"); + AnimateToPosition(player.transform.position + new Vector3(0f, 0.75f), 1.5f, 0.1f); + } + + + var inputZoomDelta = (allowUserControl && !zoomInterpolator.hasLayers) ? Input.mouseScrollDelta.y * -zoomStepSize : 0; if (inputZoomDelta != 0) { zoomInterpolator.targetValue += inputZoomDelta; @@ -70,8 +85,7 @@ public class BaseCameraController : MonoBehaviour UpdateColliderSize(); } - inputVector.x = Input.GetAxisRaw("Horizontal"); - inputVector.y = Input.GetAxisRaw("Vertical"); + inputVector = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); if (inputVector.magnitude != 0) { waitForMouseOutsideEdges = true; @@ -87,18 +101,25 @@ public class BaseCameraController : MonoBehaviour { inputVector = mouseInputVector; } - moveXInterpolator.targetValue = inputVector.x; - moveYInterpolator.targetValue = inputVector.y; - inputVector.x = moveXInterpolator.Tick(); - inputVector.y = moveYInterpolator.Tick(); } void FixedUpdate() { - if (inputVector.magnitude != 0) + xPositionInterpolator.currentValue = rigidbody.position.x; + yPositionInterpolator.currentValue = rigidbody.position.y; + if (allowUserControl && !xPositionInterpolator.hasLayers && !yPositionInterpolator.hasLayers) { - rigidbody.MovePosition(transform.position + inputVector * moveSpeed * zoomRatio * Time.fixedDeltaTime); + if (inputVector.x != 0) + { + xPositionInterpolator.targetValue = rigidbody.position.x + inputVector.x * zoomRatio * inputVelocity; + } + if (inputVector.y != 0) + { + yPositionInterpolator.targetValue = rigidbody.position.y + inputVector.y * zoomRatio * inputVelocity; + } } + var targetPos = new Vector3(xPositionInterpolator.Tick(), yPositionInterpolator.Tick()); + rigidbody.MovePosition(targetPos); } void UpdateColliderSize() diff --git a/Assets/Scripts/Box.cs b/Assets/Scripts/Box.cs index 415eb2a..615d29b 100644 --- a/Assets/Scripts/Box.cs +++ b/Assets/Scripts/Box.cs @@ -1,5 +1,7 @@ +using System; using UnityEngine; +[Serializable] public readonly struct Box { public readonly Vector3 bottomLeft; diff --git a/Assets/Scripts/Interpolator.cs b/Assets/Scripts/Interpolator.cs index 4fe29f2..5e14bd4 100644 --- a/Assets/Scripts/Interpolator.cs +++ b/Assets/Scripts/Interpolator.cs @@ -19,13 +19,13 @@ public class Interpolator } } public bool running { get; private set; } + public float currentValue; + public float velocity; private float duration; private float minValue; private float maxValue; - private float currentValue; private float _targetValue; - private float velocity; public Interpolator(float duration) : this(duration, 0) { } @@ -39,8 +39,7 @@ public class Interpolator this.minValue = minValue; this.maxValue = maxValue; currentValue = startValue; - _targetValue = targetValue; - running = !Mathf.Approximately(startValue, targetValue); + this.targetValue = targetValue; } public float Tick() @@ -48,18 +47,15 @@ public class Interpolator if (running) { currentValue = Mathf.SmoothDamp(currentValue, _targetValue, ref velocity, duration); - if (Mathf.Abs(velocity) < 0.001f) + if (Mathf.Abs(velocity) < 0.01f) { running = false; currentValue = targetValue; } } - return GetCurrentValue(); - } - - public float GetCurrentValue() - { return currentValue; } + public override string ToString() => $"Interpolator{{ Running: {running} Duration: {duration} Current Value: {currentValue} Target Value: {targetValue} Velocity: {velocity} }}"; + } diff --git a/Assets/Scripts/LayeredInterpolator.cs b/Assets/Scripts/LayeredInterpolator.cs new file mode 100644 index 0000000..0042f04 --- /dev/null +++ b/Assets/Scripts/LayeredInterpolator.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +[Serializable] +public class LayeredInterpolator +{ + + private List<Interpolator> interpolators = new List<Interpolator>(); + + public bool hasLayers + { + get => interpolators.Count >= 2; + } + + public bool running + { + get => interpolators.Any(i => i.running); + } + public float currentValue + { + get => GetCurrentInterpolator().currentValue; + set => GetCurrentInterpolator().currentValue = value; + } + public float targetValue + { + get => GetCurrentInterpolator().targetValue; + set => GetCurrentInterpolator().targetValue = value; + } + public float velocity + { + get => GetCurrentInterpolator().velocity; + set => GetCurrentInterpolator().velocity = value; + } + + public LayeredInterpolator(Interpolator baseInterpolator) + { + interpolators.Add(baseInterpolator); + } + + public void PushInterpolator(Interpolator newInterpolator) + { + if (newInterpolator.running) + { + interpolators.Add(newInterpolator); + } + } + + public void PopInterpolator() + { + if (interpolators.Count >= 2) + { + interpolators.RemoveAt(interpolators.Count - 1); + } + } + + public float Tick() + { + Interpolator current = GetCurrentInterpolator(); + float tickValue = current.Tick(); + for (var i = 0; i < interpolators.Count - 1; i++) + { + var interpolator = interpolators[i]; + interpolator.velocity = current.velocity; + interpolator.currentValue = tickValue; + if (i == 0) + { + interpolator.targetValue = tickValue; + } + } + while (!GetCurrentInterpolator().running && interpolators.Count >= 2) + { + PopInterpolator(); + } + return tickValue; + } + + private Interpolator GetCurrentInterpolator() + { + return interpolators.Last(); + } + +} diff --git a/Assets/Scripts/LayeredInterpolator.cs.meta b/Assets/Scripts/LayeredInterpolator.cs.meta new file mode 100644 index 0000000..2836f0c --- /dev/null +++ b/Assets/Scripts/LayeredInterpolator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23fcc68f9aec3c7468d2ba352e9cc26a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab