// 04.10.2021 11:00 using System; using System.Threading.Tasks; using UnityEngine; public class ThresholdedPositioner : MonoBehaviour { #region Inspector Properties [Header("Config Values")] [Tooltip("Sets the desired position relative to target.")] [SerializeField] private Vector3 offsetToTarget; [Tooltip("Should the position be fixed on height of the camera?")] [SerializeField] private bool keepOnCamHeight; [Tooltip("Specifies the desired OnEnable behaviour.")] [SerializeField] private EEnablingBehaviour enablingBehaviour = EEnablingBehaviour.Transition; [Tooltip("Specifies the delay in seconds before initializing.")] [SerializeField] private float initDelay = 0.03f; [Tooltip("Specifies how fast the object will move.")] [SerializeField] private float movingSpeed = 4f; [Tooltip("Distance from desiredPos which will start movement.")] [SerializeField] private float startMovingDistance = 0.2f; [Tooltip("Distance to desiredPos which will stop movement.")] [SerializeField] private float stopMovingDistance = 0.02f; [Tooltip("If keepAwayFromTransform is set: Minimal distance to keepAwayFromTransform.")] [SerializeField] private float keepAwayDistance = 0.5f; [Header("Scene Objects")] [Tooltip("Uses camera if not set")] [SerializeField] private Transform target; [Tooltip("Stays away from this transform")] [SerializeField] private Transform keepAwayTransform; #endregion #region Public Properties #endregion #region Private Properties private Camera cam; private bool isInitialized = false; private bool isMoving = false; #endregion #region Framework Functions void Awake() { this.cam = Camera.main; } void OnEnable() { this.initPositionerWithDelay(); } void Update() { if (this.isInitialized) { this.updateIsMoving(); if (this.isMoving) { this.updatePosition(); } if (this.keepAwayTransform != null) { this.ensureMinDistanceToKeepAwayTransform(); } } } void OnDisable() { this.isInitialized = false; } #endregion #region Events #endregion #region Public Functions public void OverrideEnablingBehaviour(EEnablingBehaviour newBehaviour) { this.enablingBehaviour = newBehaviour; } public void OverrideStartMovingDistance(float newStartMovingDistance) { this.startMovingDistance = newStartMovingDistance; } public void OverrideStopMovingDistance(float newStopMovingDistance) { this.stopMovingDistance = newStopMovingDistance; } public void OverrideMovingSpeed(float newMovingSpeed) { this.movingSpeed = newMovingSpeed; } public void OverrideKeepAwayFromTransform(Transform _keepAwayTransform, float _keepAwayDistance) { this.keepAwayTransform = _keepAwayTransform; this.keepAwayDistance = _keepAwayDistance; } public void JumpToDesiredPosition() { this.transform.position = this.getDesiredPosition(); } #endregion #region Private Functions private async void initPositionerWithDelay() { await Task.Delay(TimeSpan.FromSeconds(this.initDelay)); if (this.enablingBehaviour == EEnablingBehaviour.Transition) { this.isMoving = true; } if (this.enablingBehaviour == EEnablingBehaviour.Hold) { this.isMoving = false; } if (this.enablingBehaviour == EEnablingBehaviour.Jump) { this.transform.position = this.getDesiredPosition(); } this.isInitialized = true; } private Vector3 getDesiredPosition() { // Ensure that we always have a target (in case this gets called before init) if (this.target == null) { this.target = this.cam.transform; } Vector3 desiredPos = this.target.position + this.target.right * this.offsetToTarget.x + this.target.up * this.offsetToTarget.y + this.target.forward * this.offsetToTarget.z; if (this.keepOnCamHeight) { // Override y position to keep on Cam height desiredPos.y = this.cam.transform.position.y; // Check if distance is still sufficient after overriding y pos float distance = Vector3.Distance(desiredPos, this.target.position); if (distance < this.offsetToTarget.z) { desiredPos = (desiredPos - this.target.position).normalized * this.offsetToTarget.z + this.target.position; //Vector3 newPos = (this.transform.position - this.keepAwayTransform.position).normalized * this.keepAwayDistance + this.keepAwayTransform.position; } } return desiredPos; } private void updateIsMoving() { float distance = Vector3.Distance(this.transform.position, this.getDesiredPosition()); if (this.isMoving && distance < this.stopMovingDistance) { this.isMoving = false; } else if (!this.isMoving && distance > this.startMovingDistance) { this.isMoving = true; } } private void updatePosition() { Vector3 newPosition = Vector3.Lerp(this.transform.position, this.getDesiredPosition(), this.movingSpeed * Time.deltaTime); if (this.keepAwayTransform != null) { float distance = Vector3.Distance(newPosition, this.keepAwayTransform.position); if (distance < this.keepAwayDistance) { // Getting too close to keep away from transform -> don't move newPosition = this.transform.position; } } this.transform.position = newPosition; } private void ensureMinDistanceToKeepAwayTransform() { float distance = Vector3.Distance(this.transform.position, this.keepAwayTransform.position); if (distance < this.keepAwayDistance) { Vector3 newPos = (this.transform.position - this.keepAwayTransform.position).normalized * this.keepAwayDistance + this.keepAwayTransform.position; this.transform.position = newPos; } } #endregion }