You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
4.3 KiB

5 years ago
  1. using UnityEngine;
  2. using System;
  3. public class BezierSpline : MonoBehaviour {
  4. [SerializeField]
  5. private Vector3[] points;
  6. [SerializeField]
  7. private BezierControlPointMode[] modes;
  8. [SerializeField]
  9. private bool loop;
  10. public bool Loop {
  11. get {
  12. return loop;
  13. }
  14. set {
  15. loop = value;
  16. if (value == true) {
  17. modes[modes.Length - 1] = modes[0];
  18. SetControlPoint(0, points[0]);
  19. }
  20. }
  21. }
  22. public int ControlPointCount {
  23. get {
  24. return points.Length;
  25. }
  26. }
  27. public Vector3 GetControlPoint (int index) {
  28. return points[index];
  29. }
  30. public void SetControlPoint (int index, Vector3 point) {
  31. if (index % 3 == 0) {
  32. Vector3 delta = point - points[index];
  33. if (loop) {
  34. if (index == 0) {
  35. points[1] += delta;
  36. points[points.Length - 2] += delta;
  37. points[points.Length - 1] = point;
  38. }
  39. else if (index == points.Length - 1) {
  40. points[0] = point;
  41. points[1] += delta;
  42. points[index - 1] += delta;
  43. }
  44. else {
  45. points[index - 1] += delta;
  46. points[index + 1] += delta;
  47. }
  48. }
  49. else {
  50. if (index > 0) {
  51. points[index - 1] += delta;
  52. }
  53. if (index + 1 < points.Length) {
  54. points[index + 1] += delta;
  55. }
  56. }
  57. }
  58. points[index] = point;
  59. EnforceMode(index);
  60. }
  61. public BezierControlPointMode GetControlPointMode (int index) {
  62. return modes[(index + 1) / 3];
  63. }
  64. public void SetControlPointMode (int index, BezierControlPointMode mode) {
  65. int modeIndex = (index + 1) / 3;
  66. modes[modeIndex] = mode;
  67. if (loop) {
  68. if (modeIndex == 0) {
  69. modes[modes.Length - 1] = mode;
  70. }
  71. else if (modeIndex == modes.Length - 1) {
  72. modes[0] = mode;
  73. }
  74. }
  75. EnforceMode(index);
  76. }
  77. private void EnforceMode (int index) {
  78. int modeIndex = (index + 1) / 3;
  79. BezierControlPointMode mode = modes[modeIndex];
  80. if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1)) {
  81. return;
  82. }
  83. int middleIndex = modeIndex * 3;
  84. int fixedIndex, enforcedIndex;
  85. if (index <= middleIndex) {
  86. fixedIndex = middleIndex - 1;
  87. if (fixedIndex < 0) {
  88. fixedIndex = points.Length - 2;
  89. }
  90. enforcedIndex = middleIndex + 1;
  91. if (enforcedIndex >= points.Length) {
  92. enforcedIndex = 1;
  93. }
  94. }
  95. else {
  96. fixedIndex = middleIndex + 1;
  97. if (fixedIndex >= points.Length) {
  98. fixedIndex = 1;
  99. }
  100. enforcedIndex = middleIndex - 1;
  101. if (enforcedIndex < 0) {
  102. enforcedIndex = points.Length - 2;
  103. }
  104. }
  105. Vector3 middle = points[middleIndex];
  106. Vector3 enforcedTangent = middle - points[fixedIndex];
  107. if (mode == BezierControlPointMode.Aligned) {
  108. enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);
  109. }
  110. points[enforcedIndex] = middle + enforcedTangent;
  111. }
  112. public int CurveCount {
  113. get {
  114. return (points.Length - 1) / 3;
  115. }
  116. }
  117. public Vector3 GetPoint (float t) {
  118. int i;
  119. if (t >= 1f) {
  120. t = 1f;
  121. i = points.Length - 4;
  122. }
  123. else {
  124. t = Mathf.Clamp01(t) * CurveCount;
  125. i = (int)t;
  126. t -= i;
  127. i *= 3;
  128. }
  129. return transform.TransformPoint(Bezier.GetPoint(points[i], points[i + 1], points[i + 2], points[i + 3], t));
  130. }
  131. public Vector3 GetVelocity (float t) {
  132. int i;
  133. if (t >= 1f) {
  134. t = 1f;
  135. i = points.Length - 4;
  136. }
  137. else {
  138. t = Mathf.Clamp01(t) * CurveCount;
  139. i = (int)t;
  140. t -= i;
  141. i *= 3;
  142. }
  143. return transform.TransformPoint(Bezier.GetFirstDerivative(points[i], points[i + 1], points[i + 2], points[i + 3], t)) - transform.position;
  144. }
  145. public Vector3 GetDirection (float t) {
  146. return GetVelocity(t).normalized;
  147. }
  148. public void AddCurve () {
  149. Vector3 point = points[points.Length - 1];
  150. Array.Resize(ref points, points.Length + 3);
  151. point.x += 1f;
  152. points[points.Length - 3] = point;
  153. point.x += 1f;
  154. points[points.Length - 2] = point;
  155. point.x += 1f;
  156. points[points.Length - 1] = point;
  157. Array.Resize(ref modes, modes.Length + 1);
  158. modes[modes.Length - 1] = modes[modes.Length - 2];
  159. EnforceMode(points.Length - 4);
  160. if (loop) {
  161. points[points.Length - 1] = points[0];
  162. modes[modes.Length - 1] = modes[0];
  163. EnforceMode(0);
  164. }
  165. }
  166. public void Reset () {
  167. points = new Vector3[] {
  168. new Vector3(1f, 0f, 0f),
  169. new Vector3(2f, 0f, 0f),
  170. new Vector3(3f, 0f, 0f),
  171. new Vector3(4f, 0f, 0f)
  172. };
  173. modes = new BezierControlPointMode[] {
  174. BezierControlPointMode.Free,
  175. BezierControlPointMode.Free
  176. };
  177. }
  178. }