using System; using System.ComponentModel; using System.Runtime.CompilerServices; using KitsuneCafe.Sys; using UnityEngine; namespace KitsuneCafe.Entities { public class Spring : MonoBehaviour, INotifyPropertyChanged { [SerializeField] private new Rigidbody rigidbody; [SerializeField] private Raycaster raycaster; // [SerializeField] // private float rayLength = 1.5f; [SerializeField] private float rideHeight = 1f; [SerializeField] private float rideSpringStrength; [SerializeField] private float rideSpringDamper; // [SerializeField] // private Vector3 rayOffset = Vector3.zero; // [SerializeField] // private Vector3 down = Vector3.down; // [SerializeField] // private LayerMask layerMask; private bool isColliding = false; public bool IsColliding { get => isColliding; private set { if (isColliding != value) { isColliding = value; Notify(); } } } private bool isAtRideHeight = false; public bool IsAtRideHeight { get => isAtRideHeight; private set { if (isAtRideHeight != value) { isAtRideHeight = value; Notify(); } } } private float relativeVelocity; private float targetDistance; private float springForce; public event PropertyChangedEventHandler PropertyChanged; private void Reset() { rigidbody = GetComponent(); } private void FixedUpdate() { IsColliding = raycaster.Raycast(out var hit); if (isColliding) { relativeVelocity = RelativeVelocity(raycaster.Direction, rigidbody, hit.rigidbody); targetDistance = hit.distance - rideHeight; springForce = (targetDistance * rideSpringStrength) - (relativeVelocity * rideSpringDamper); IsAtRideHeight = Approximately(springForce, Physics.gravity.y, 0.001f); rigidbody.AddForce(raycaster.Direction * springForce); } } private static bool Approximately(float a, float b, float e = float.Epsilon) => Math.Abs(a - b) < e; private static float RelativeVelocity(Vector3 direction, Rigidbody a, Rigidbody b) { var aVelocity = GetVelocity(a); var bVelocity = GetVelocity(b); var aDirVelocity = Vector3.Dot(direction, aVelocity); var bDirVelocity = Vector3.Dot(direction, bVelocity); return aDirVelocity - bDirVelocity; } private static Vector3 GetVelocity(Rigidbody rb) => rb == null ? Vector3.zero : rb.linearVelocity; private void Notify([CallerMemberName] string name = default) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } private void OnDrawGizmos() { if (raycaster == null) { return; } var origin = raycaster.transform.position; Gizmos.color = Color.white; Gizmos.DrawRay(origin, raycaster.Direction * rideHeight); } } }