242 lines
8.5 KiB
C#
242 lines
8.5 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Splines;
|
|
|
|
namespace OmniVehicleAi
|
|
{
|
|
public class PathProgressTracker : MonoBehaviour
|
|
{
|
|
public AIVehicleController aiVehicleController;
|
|
public SplineContainer splineContainer; // The spline container holding the spline
|
|
|
|
[Header("Offsets")]
|
|
public float offset_A = 15f;
|
|
public float offset_AB = 10f;
|
|
public float offset_BC = 10f;
|
|
|
|
public Vector3 progressPoint { get; private set; }
|
|
public Vector3 progressTangent { get; private set; }
|
|
public Vector3 progressRight { get; private set; }
|
|
|
|
public float progressDistance { get; private set; } // The progress along the spline.
|
|
|
|
[HideInInspector] public Vector3 A { get; private set; }
|
|
[HideInInspector] public Vector3 B { get; private set; }
|
|
[HideInInspector] public Vector3 C { get; private set; }
|
|
[HideInInspector] public Vector3 D { get; private set; }
|
|
private float speed;
|
|
|
|
|
|
[Header("Lap Settings")]
|
|
public int totalLaps = 3; // Total number of laps for the race
|
|
public int currentLap = 1; // Current lap count
|
|
public bool loopCircuit = true; // If true, the circuit loops for multiple laps
|
|
|
|
private Spline spline;
|
|
private float splineLength;
|
|
|
|
public UnityEvent OnLapCompleted; // Event for lap completion
|
|
public UnityEvent OnAllLapsCompleted; // Event for all laps completion
|
|
|
|
private void Start()
|
|
{
|
|
if (aiVehicleController == null)
|
|
{
|
|
Debug.LogError("AIVehicleController component is missing on this GameObject.");
|
|
}
|
|
|
|
if (splineContainer == null)
|
|
{
|
|
Debug.LogError("SplineContainer not assigned and none found in the scene.");
|
|
enabled = false;
|
|
return;
|
|
}
|
|
|
|
spline = splineContainer.Splines[0];
|
|
if (spline == null)
|
|
{
|
|
Debug.LogError("SplineContainer does not contain any splines.");
|
|
enabled = false;
|
|
return;
|
|
}
|
|
|
|
splineLength = spline.GetLength();
|
|
|
|
ResetProgress();
|
|
}
|
|
|
|
public void ResetProgress()
|
|
{
|
|
progressDistance = 0f;
|
|
currentLap = 1; // Reset the lap count
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (aiVehicleController == null || spline == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
speed = aiVehicleController.LocalVehiclevelocity.magnitude;
|
|
|
|
// If loopCircuit is true, the positions can wrap around the spline.
|
|
if (loopCircuit)
|
|
{
|
|
A = GetSplinePoint((progressDistance + offset_A) % splineLength);
|
|
B = GetSplinePoint((progressDistance + offset_A + offset_AB) % splineLength);
|
|
C = GetSplinePoint((progressDistance + offset_A + offset_AB + offset_BC) % splineLength);
|
|
D = GetSplinePoint((progressDistance + offset_A + offset_AB + offset_BC + speed) % splineLength);
|
|
}
|
|
else
|
|
{
|
|
// Clamp the positions at the end of the spline when it's not looping.
|
|
A = GetSplinePoint(Mathf.Min(progressDistance + offset_A, splineLength));
|
|
B = GetSplinePoint(Mathf.Min(progressDistance + offset_A + offset_AB, splineLength));
|
|
C = GetSplinePoint(Mathf.Min(progressDistance + offset_A + offset_AB + offset_BC, splineLength));
|
|
D = GetSplinePoint(Mathf.Min(progressDistance + offset_A + offset_AB + offset_BC + speed, splineLength));
|
|
}
|
|
|
|
// Get the current progress point and tangent
|
|
progressPoint = GetSplinePoint(progressDistance % splineLength);
|
|
progressTangent = GetSplineTangent(progressDistance % splineLength);
|
|
progressRight = Vector3.Cross(progressTangent, Vector3.up).normalized;
|
|
|
|
Vector3 progressDelta = progressPoint - transform.position;
|
|
|
|
// Adjust progress distance based on direction
|
|
if (Vector3.Dot(progressDelta, progressTangent) < 0)
|
|
{
|
|
progressDistance += progressDelta.magnitude * 0.5f;
|
|
}
|
|
|
|
// Check if we've completed a lap
|
|
if (progressDistance >= splineLength)
|
|
{
|
|
CompleteLap();
|
|
}
|
|
}
|
|
|
|
private void CompleteLap()
|
|
{
|
|
if (loopCircuit)
|
|
{
|
|
progressDistance -= splineLength;// Continue with remaining distance past the spline length
|
|
}
|
|
|
|
currentLap++;
|
|
|
|
OnLapCompleted?.Invoke();
|
|
|
|
if(currentLap > totalLaps)
|
|
{
|
|
OnAllLapsCompleted?.Invoke();
|
|
}
|
|
|
|
// Handle looping logic if enabled
|
|
if (loopCircuit && currentLap > totalLaps)
|
|
{
|
|
currentLap = 1; // Restart from the first lap
|
|
}
|
|
}
|
|
|
|
public Vector3 GetClosestPointOnCircuit(Vector3 point)
|
|
{
|
|
if (spline == null)
|
|
{
|
|
Debug.LogError("Spline is not initialized.");
|
|
return Vector3.zero;
|
|
}
|
|
|
|
float closestDistance = float.MaxValue;
|
|
Vector3 closestPoint = Vector3.zero;
|
|
|
|
for (int i = 0; i < spline.Count - 1; i++)
|
|
{
|
|
float t0 = (float)i / (spline.Count - 1);
|
|
float t1 = (float)(i + 1) / (spline.Count - 1);
|
|
int steps = 10;
|
|
|
|
for (int j = 0; j <= steps; j++)
|
|
{
|
|
float t = Mathf.Lerp(t0, t1, j / (float)steps);
|
|
Vector3 splinePoint = spline.EvaluatePosition(t);
|
|
float distance = Vector3.Distance(point, splinePoint);
|
|
if (distance < closestDistance)
|
|
{
|
|
closestDistance = distance;
|
|
closestPoint = splinePoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
return closestPoint;
|
|
}
|
|
|
|
public Vector3 GetSplinePoint(float distance)
|
|
{
|
|
if (splineContainer == null)
|
|
{
|
|
Debug.LogError("SplineContainer is not assigned.");
|
|
return Vector3.zero;
|
|
}
|
|
float normalizedDistance = distance / splineLength;
|
|
return splineContainer.EvaluatePosition(normalizedDistance);
|
|
}
|
|
|
|
public Vector3 GetSplineTangent(float distance)
|
|
{
|
|
if (splineContainer == null)
|
|
{
|
|
Debug.LogError("SplineContainer is not assigned.");
|
|
return Vector3.forward;
|
|
}
|
|
float normalizedDistance = distance / splineLength;
|
|
|
|
Vector3 splineTangent = splineContainer.EvaluateTangent(normalizedDistance);
|
|
|
|
return splineTangent.normalized;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if(aiVehicleController.AiMode != AIVehicleController.Ai_Mode.PathFollow) { return; }
|
|
|
|
if (Application.isPlaying)
|
|
{
|
|
Gizmos.color = Color.cyan;
|
|
Gizmos.DrawLine(transform.position, A);
|
|
Gizmos.color = Color.blue;
|
|
Gizmos.DrawWireSphere(progressPoint, 0.2f);
|
|
Gizmos.DrawLine(transform.position, progressPoint);
|
|
Gizmos.color = new Color(0.8f, 0.1f, 0, 0.8f);
|
|
Gizmos.DrawSphere(A, 1);
|
|
Gizmos.DrawSphere(B, 1);
|
|
Gizmos.DrawSphere(C, 1);
|
|
Gizmos.DrawSphere(D, 1);
|
|
|
|
Gizmos.color = Color.green;
|
|
Gizmos.DrawLine(A, B);
|
|
Gizmos.DrawLine(B, C);
|
|
Gizmos.DrawLine(C, D);
|
|
}
|
|
else
|
|
{
|
|
Vector3 tempA = transform.position + transform.forward * offset_A;
|
|
Vector3 tempB = transform.position + transform.forward * (offset_A + offset_AB);
|
|
Vector3 tempC = transform.position + transform.forward * (offset_A + offset_AB + offset_BC);
|
|
|
|
Gizmos.color = new Color(0.8f, 0.1f, 0, 0.8f);
|
|
Gizmos.DrawSphere(tempA, 1);
|
|
Gizmos.DrawSphere(tempB, 1);
|
|
Gizmos.DrawSphere(tempC, 1);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
}
|