rabidus-test/Assets/Dreamteck/Splines/Examples/Junctions/Scripts/Wagon.cs

205 lines
7.9 KiB
C#
Raw Normal View History

2023-07-24 16:38:13 +03:00
namespace Dreamteck.Splines.Examples
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wagon : MonoBehaviour
{
//A helper class which contains an information for a spline and the points
//between which the spline is traversed (start and end)
//If one of the points is equal to -1 it means that there is no constraint
public class SplineSegment
{
public SplineComputer spline;
public int start = -1, end = -1;
public Spline.Direction direction;
public SplineSegment(SplineComputer spline, int entryPoint, Spline.Direction direction)
{
this.spline = spline;
start = entryPoint;
this.direction = direction;
}
public SplineSegment(SplineSegment input)
{
spline = input.spline;
start = input.start;
end = input.end;
direction = input.direction;
}
public double Travel(double percent, float distance, Spline.Direction direction, out float moved, bool loop)
{
double max = direction == Spline.Direction.Forward ? 1.0 : 0.0;
if (start >= 0) max = spline.GetPointPercent(start);
return TravelClamped(percent, distance, direction, max, out moved, loop);
}
//Travel the spline segment by automatically starting at the segment's exit (end)
public double Travel(float distance, Spline.Direction direction, out float moved, bool loop)
{
double startPercent = spline.GetPointPercent(end);
double max = direction == Spline.Direction.Forward ? 1.0 : 0.0;
if (start >= 0) max = spline.GetPointPercent(start);
return TravelClamped(startPercent, distance, direction, max, out moved, loop);
}
//Travel the spline segment while not exceeding the "max" percent
//It also supports looping splines unlike the standard Travel methods found in SplineComputer and SplineUser
double TravelClamped(double percent, float distance, Spline.Direction direction, double max, out float moved, bool loop)
{
moved = 0f;
float traveled = 0f;
double result = spline.Travel(percent, distance, out traveled, direction);
moved += traveled;
if (loop && moved < distance) {
if (direction == Spline.Direction.Forward && Mathf.Approximately((float)result, 1f))
{
result = spline.Travel(0.0, distance - moved, out traveled, direction);
} else if (direction == Spline.Direction.Backward && Mathf.Approximately((float)result, 0f))
{
result = spline.Travel(1.0, distance - moved, out traveled, direction);
}
moved += traveled;
}
if (direction == Spline.Direction.Forward && percent <= max)
{
if (result > max)
{
moved -= spline.CalculateLength(result, max);
result = max;
}
}
else if (direction == Spline.Direction.Backward && percent >= max)
{
if (result < max)
{
moved -= spline.CalculateLength(max, result);
result = max;
}
}
return result;
}
}
SplineTracer tracer;
public bool isEngine = false;
public Wagon back;
public float offset = 0f;
Wagon front;
SplineSegment segment, tempSegment;
private void Awake()
{
tracer = GetComponent<SplineTracer>();
//Wagon compoenent that is attached to the train engine and is marked as "isEngine" will
//run a recursive setup for the rest of the wagons
if (isEngine) SetupRecursively(null, new SplineSegment(tracer.spline, -1, tracer.direction));
}
void SetupRecursively(Wagon frontWagon, SplineSegment inputSegment)
{
front = frontWagon;
segment = inputSegment;
if (back != null) back.SetupRecursively(this, segment);
}
public void UpdateOffset()
{
ApplyOffset();
if (back != null) back.UpdateOffset();
}
Wagon GetRootWagon()
{
Wagon current = this;
while (current.front != null) current = current.front;
return current;
}
void ApplyOffset()
{
if (isEngine)
{
ResetSegments();
return;
}
float totalMoved = 0f, moved = 0f;
double start = front.tracer.UnclipPercent(front.tracer.result.percent);
//Travel backwards along the front wagon's spline
Spline.Direction inverseDirection = front.segment.direction;
InvertDirection(ref inverseDirection);
SplineComputer spline = front.segment.spline;
double percent = front.segment.Travel(start, offset, inverseDirection, out moved, front.segment.spline.isClosed);
totalMoved += moved;
//Finalize if moved fully without reaching a spline end or a junction
if (Mathf.Approximately(totalMoved, offset))
{
if (segment != front.segment)
{
if (back != null) back.segment = segment;
}
if(segment != front.segment) segment = front.segment;
ApplyTracer(spline, percent, front.tracer.direction);
return;
}
//Otherwise, move along the current recorded spline segment
if (segment != front.segment)
{
inverseDirection = segment.direction;
InvertDirection(ref inverseDirection);
spline = segment.spline;
percent = segment.Travel(offset - totalMoved, inverseDirection, out moved, segment.spline.isClosed);
totalMoved += moved;
}
ApplyTracer(spline, percent, segment.direction);
}
void ResetSegments()
{
Wagon current = back;
bool same = true;
while (current != null)
{
if(current.segment != segment)
{
same = false;
break;
}
current = current.back;
}
//if all wagons are on the same segment, remove the segment entrance so that they can loop
if(same) segment.start = -1;
}
void ApplyTracer(SplineComputer spline, double percent, Spline.Direction direction)
{
bool rebuild = tracer.spline != spline;
tracer.spline = spline;
if (rebuild) tracer.RebuildImmediate();
tracer.direction = direction;
tracer.SetPercent(tracer.ClipPercent(percent));
}
public void EnterSplineSegment(int previousSplineExitPoint, SplineComputer spline, int entryPoint, Spline.Direction direction)
{
if (!isEngine) return;
if (back != null)
{
segment.end = previousSplineExitPoint;
back.segment = segment;
}
segment = new SplineSegment(spline, entryPoint, direction);
}
static void InvertDirection(ref Spline.Direction direction)
{
if (direction == Spline.Direction.Forward) direction = Spline.Direction.Backward;
else direction = Spline.Direction.Forward;
}
}
}