205 lines
7.9 KiB
C#
205 lines
7.9 KiB
C#
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|