Files
2025-06-09 23:23:13 +08:00

122 lines
3.5 KiB
C#

using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Splines;
using static UnityEngine.Splines.SplineComponent;
namespace JBooth.MicroVerseCore.Roads.Demo
{
public class MoveAlongSpline : MonoBehaviour
{
[Header("Components")]
public GameObject npc;
public SplineContainer splineContainer;
public Vector3 pathOffset;
[Header("Speed Settings")]
public float speed = 1.0f;
public float minSpeed = 1f;
public float maxSpeed = 10f;
[Header("Manual Adjustment")]
#region mousewheel
[Tooltip("Manual speed adjustment via mouse wheel")]
public bool mouseWheelSpeedChange = false;
[Tooltip("Factor that's applied to the mouse wheel's delta increment")]
public float mouseWheelFactor = 1.0f;
#endregion mousewheel
[Header("Alignment")]
public bool useRoll = true;
public MoveAlongSpline parent;
public float parentOffsetT = 0f;
private SplinePath path;
private float pathLength;
private float t = 0f;
#region axis alignment
public AlignAxis axisForward = AlignAxis.ZAxis;
public AlignAxis axisUp = AlignAxis.YAxis;
readonly float3[] axisToVector = new float3[] { math.right(), math.up(), math.forward(), math.left(), math.down(), math.back() };
protected float3 GetAxis(AlignAxis axis)
{
return axisToVector[(int)axis];
}
#endregion axis alignment
void Start()
{
if (npc == null)
{
npc = this.gameObject;
}
var container1Transform = splineContainer.transform.localToWorldMatrix;
path = new SplinePath(new[]
{
new SplineSlice<Spline>(splineContainer.Splines[0], new SplineRange(/* start (inclusive) */ 0, /* count; +1 for the closed loop segment */ splineContainer.Splines[0].Count + 1), container1Transform),
});
pathLength = path.GetLength();
}
void FixedUpdate()
{
if(parent != null)
{
t = parent.GetT() + parentOffsetT / pathLength;
}
Vector3 pos = path.EvaluatePosition(t);
npc.transform.position = pos + pathOffset;
Vector3 direction = path.EvaluateTangent(t);
Vector3 forward = Vector3.Normalize(path.EvaluateTangent(t));
Vector3 up = path.EvaluateUpVector(t);
var remappedForward = GetAxis(axisForward); // new Vector3(0, 0, 1);
var remappedUp = GetAxis(axisUp); // new Vector3(0, 1, 0);
var axisRemapRotation = Quaternion.Inverse(Quaternion.LookRotation(remappedForward, remappedUp));
npc.transform.rotation = Quaternion.LookRotation(forward, up) * axisRemapRotation;
float angle = Vector3.Angle(transform.up, Vector3.up);
float distance = direction.magnitude;
float forceMagnitude = Physics.gravity.y * angle / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
speed += force.y;
if (mouseWheelSpeedChange)
{
speed += Input.mouseScrollDelta.y * mouseWheelFactor;
}
speed = Mathf.Clamp(speed, minSpeed, maxSpeed);
t = (t + speed * Time.deltaTime / pathLength) % 1f;
}
public float GetT()
{
return t;
}
}
}