canto/Assets/Scripts/Entity/Spring.cs
2025-08-16 16:17:16 -04:00

102 lines
2.8 KiB
C#

using UnityEngine;
namespace KitsuneCafe.Entities
{
public class Spring : MonoBehaviour
{
[SerializeField]
private new Rigidbody rigidbody;
[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 didRayHit;
private Vector3 relativeDown;
private float relativeVelocity;
private float targetDistance;
private float springForce;
public bool IsSpringColliding => didRayHit;
private void Reset()
{
rigidbody = GetComponent<Rigidbody>();
layerMask = LayerMask.NameToLayer("Default");
}
private void FixedUpdate()
{
relativeDown = transform.TransformDirection(this.down);
didRayHit = Raycast(relativeDown, out var hit);
if (didRayHit)
{
relativeVelocity = RelativeVelocity(down, rigidbody, hit.rigidbody);
targetDistance = hit.distance - rideHeight;
springForce = (targetDistance * rideSpringStrength) - (relativeVelocity * rideSpringDamper);
rigidbody.AddForce(relativeDown * springForce);
}
}
private bool Raycast(Vector3 direction, out RaycastHit hit)
{
return Physics.Raycast(
transform.position + rayOffset,
direction,
out hit,
rayLength,
layerMask
);
}
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)
{
return rb == null ? Vector3.zero : rb.linearVelocity;
}
private void OnDrawGizmos()
{
var origin = transform.position + rayOffset;
Gizmos.color = didRayHit ? Color.yellow : Color.red;
Gizmos.DrawRay(origin, relativeDown * rayLength);
if (didRayHit)
{
Gizmos.color = Color.green;
Gizmos.DrawRay(origin, relativeDown * rideHeight);
}
}
}
}