123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- // --------------------------------------------------------------------------------------------------------------------
- // <copyright file="Bezier.cs" company="Exit Games GmbH">
- // Part of: Photon Unity Networking Demos
- // </copyright>
- // <summary>
- // Original: http://catlikecoding.com/unity/tutorials/curves-and-splines/
- // Used in SlotRacer Demo
- // </summary>
- // <author>developer@exitgames.com</author>
- // --------------------------------------------------------------------------------------------------------------------
- using UnityEngine;
- using System;
- namespace Photon.Pun.Demo.SlotRacer.Utils
- {
- public class BezierSpline : MonoBehaviour
- {
- [SerializeField]
- private Vector3[] points;
- [SerializeField]
- private float[] lengths;
- [SerializeField]
- private float[] lengthsTime;
- public float TotalLength;
- [SerializeField]
- private BezierControlPointMode[] modes;
- [SerializeField]
- private bool loop;
- public bool Loop
- {
- get {
- return loop;
- }
- set {
- loop = value;
- if (value == true) {
- modes[modes.Length - 1] = modes[0];
- SetControlPoint(0, points[0]);
- }
- }
- }
- public int ControlPointCount
- {
- get {
- return points.Length;
- }
- }
- void Awake()
- {
- this.ComputeLengths();
- }
- public Vector3 GetControlPoint(int index)
- {
- return points[index];
- }
- public void SetControlPoint(int index, Vector3 point)
- {
- if (index % 3 == 0)
- {
- Vector3 delta = point - points[index];
- if (loop)
- {
- if (index == 0)
- {
- points[1] += delta;
- points[points.Length - 2] += delta;
- points[points.Length - 1] = point;
- }
- else if (index == points.Length - 1)
- {
- points[0] = point;
- points[1] += delta;
- points[index - 1] += delta;
- }
- else
- {
- points[index - 1] += delta;
- points[index + 1] += delta;
- }
- }
- else
- {
- if (index > 0)
- {
- points[index - 1] += delta;
- }
- if (index + 1 < points.Length)
- {
- points[index + 1] += delta;
- }
- }
- }
- points[index] = point;
- EnforceMode(index);
- }
- public BezierControlPointMode GetControlPointMode(int index)
- {
- return modes[(index + 1) / 3];
- }
- public void SetControlPointMode(int index, BezierControlPointMode mode)
- {
- int modeIndex = (index + 1) / 3;
- modes[modeIndex] = mode;
- if (loop)
- {
- if (modeIndex == 0) {
- modes[modes.Length - 1] = mode;
- }
- else if (modeIndex == modes.Length - 1) {
- modes[0] = mode;
- }
- }
- EnforceMode(index);
- }
- private void EnforceMode(int index)
- {
- int modeIndex = (index + 1) / 3;
- BezierControlPointMode mode = modes[modeIndex];
- if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1))
- {
- return;
- }
- int middleIndex = modeIndex * 3;
- int fixedIndex, enforcedIndex;
- if (index <= middleIndex)
- {
- fixedIndex = middleIndex - 1;
- if (fixedIndex < 0)
- {
- fixedIndex = points.Length - 2;
- }
- enforcedIndex = middleIndex + 1;
- if (enforcedIndex >= points.Length)
- {
- enforcedIndex = 1;
- }
- }else
- {
- fixedIndex = middleIndex + 1;
- if (fixedIndex >= points.Length)
- {
- fixedIndex = 1;
- }
- enforcedIndex = middleIndex - 1;
- if (enforcedIndex < 0)
- {
- enforcedIndex = points.Length - 2;
- }
- }
- Vector3 middle = points[middleIndex];
- Vector3 enforcedTangent = middle - points[fixedIndex];
- if (mode == BezierControlPointMode.Aligned)
- {
- enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);
- }
- points[enforcedIndex] = middle + enforcedTangent;
- }
- public int CurveCount
- {
- get {
- return (points.Length - 1) / 3;
- }
- }
- public Vector3 GetPoint(float t)
- {
- int i;
- if (t >= 1f)
- {
- t = 1f;
- i = points.Length - 4;
- }
- else
- {
- t = Mathf.Clamp01(t) * CurveCount;
- i = (int)t;
- t -= i;
- i *= 3;
- }
- return transform.TransformPoint(Bezier.GetPoint(points[i], points[i + 1], points[i + 2], points[i + 3], t));
- }
-
- public Vector3 GetVelocity(float t)
- {
- int i;
- if (t >= 1f)
- {
- t = 1f;
- i = points.Length - 4;
- }
- else
- {
- t = Mathf.Clamp01(t) * CurveCount;
- i = (int)t;
- t -= i;
- i *= 3;
- }
- return transform.TransformPoint(Bezier.GetFirstDerivative(points[i], points[i + 1], points[i + 2], points[i + 3], t)) - transform.position;
- }
-
- public Vector3 GetDirection(float t)
- {
- return GetVelocity(t).normalized;
- }
- public void AddCurve ()
- {
- Vector3 point = points[points.Length - 1];
- Array.Resize(ref points, points.Length + 3);
- point.x += 1f;
- points[points.Length - 3] = point;
- point.x += 1f;
- points[points.Length - 2] = point;
- point.x += 1f;
- points[points.Length - 1] = point;
- Array.Resize(ref modes, modes.Length + 1);
- modes[modes.Length - 1] = modes[modes.Length - 2];
- EnforceMode(points.Length - 4);
- if (loop)
- {
- points[points.Length - 1] = points[0];
- modes[modes.Length - 1] = modes[0];
- EnforceMode(0);
- }
- }
-
- public void Reset()
- {
- points = new Vector3[] {
- new Vector3(1f, 0f, 0f),
- new Vector3(2f, 0f, 0f),
- new Vector3(3f, 0f, 0f),
- new Vector3(4f, 0f, 0f)
- };
- modes = new BezierControlPointMode[] {
- BezierControlPointMode.Free,
- BezierControlPointMode.Free
- };
- }
- public void ComputeLengths()
- {
- int subDivisions = 100;
- int totalSamples = points.Length * subDivisions;
- // lets create lengths for each control point.
- this.lengths = new float[totalSamples];
- this.lengthsTime = new float[totalSamples];
- float totalDistance = 0;
- float CurrentTime = 0f;
-
- Vector3 pos;
- Vector3 lastPos = this.GetPoint (0f);
- // go from the first, to the second to last
- for (var i = 0; i < totalSamples - 1; i++)
- {
- CurrentTime = (1f * i) / totalSamples;
- pos = this.GetPoint (CurrentTime);
- float _delta = (pos - lastPos).magnitude;
- totalDistance += _delta ;
- this.lengths [i] = totalDistance;
- this.lengthsTime [i] = CurrentTime;
- lastPos = pos;
- }
- this.TotalLength = totalDistance;
- }
- public Vector3 GetPositionAtDistance(float distance,bool reverse = false)
- {
- if (reverse)
- {
- distance = this.TotalLength - distance;
- }
- distance = Mathf.Repeat (distance, this.TotalLength);
- // make sure that we are within the total distance of the points
- if(distance <= 0) return points[0];
- if(distance >= this.TotalLength) return points[points.Length - 1];
- // lets find the first point that is below the distance
- // but, who's next point is above the distance
- var index = 0;
- while (index < lengths.Length -1 && lengths[index] < distance)
- index++;
- // Debug.Log("Index ="+index);
- // get the percentage of travel from the current length to the next
- // where the distance is.
- //var deltaAmount = Mathf.InverseLerp(lengths[index-1], lengths[index], distance);
- float deltaDistanceRatio = (distance-lengths[index-1])/(lengths [index] - lengths [index - 1]) ;
- float deltaTime = (lengthsTime [index] - lengthsTime [index - 1]) * deltaDistanceRatio;
- //float splineDistance = (lengths [index - 1] + (lengths [index] - lengths [index - 1]) * amount) / this.TotalLength;
- return GetPoint(this.lengthsTime[index]+deltaTime);
- // we use that, to get the actual point
- // return Vector3.Lerp(points[index-1], points[index], amount);
- }
- }
- }
|