123 lines
2.9 KiB
C#
123 lines
2.9 KiB
C#
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<Rigidbody>();
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|