5 using System.Collections.Generic;
12 [Header(
"Spline Settings")]
17 private bool alignControlPoints =
true;
19 public bool AlignControlPoints
21 get {
return alignControlPoints; }
24 if (alignControlPoints != value)
26 alignControlPoints = value;
27 ForceUpdateAlignment();
32 public override int NumPoints
42 if (AlignControlPoints)
44 for (
int i = 0; i < NumPoints; i++)
46 ForceUpdateAlignment(i);
51 private void ForceUpdateAlignment(
int pointIndex)
53 if (AlignControlPoints)
55 int prevControlPoint = 0;
56 int changedControlPoint = 0;
57 int midPointIndex = ((pointIndex + 1) / 3) * 3;
59 if (pointIndex <= midPointIndex)
61 prevControlPoint = midPointIndex - 1;
62 changedControlPoint = midPointIndex + 1;
66 prevControlPoint = midPointIndex + 1;
67 changedControlPoint = midPointIndex - 1;
72 if (changedControlPoint < 0)
74 changedControlPoint = (NumPoints - 1) + changedControlPoint;
76 else if (changedControlPoint >= NumPoints)
78 changedControlPoint = changedControlPoint % (NumPoints - 1);
81 if (prevControlPoint < 0)
83 prevControlPoint = (NumPoints - 1) + prevControlPoint;
85 else if (prevControlPoint >= NumPoints)
87 prevControlPoint = prevControlPoint % (NumPoints - 1);
90 Vector3 midPoint = points[midPointIndex].
Point;
91 Vector3 tangent = midPoint - points[prevControlPoint].
Point;
92 tangent = tangent.normalized * Vector3.Distance(midPoint, points[changedControlPoint].Point);
93 points[changedControlPoint].
Point = midPoint + tangent;
96 else if (changedControlPoint >= 0 && changedControlPoint < NumPoints && prevControlPoint >= 0 && prevControlPoint < NumPoints)
98 Vector3 midPoint = points[midPointIndex].
Point;
99 Vector3 tangent = midPoint - points[prevControlPoint].
Point;
100 tangent = tangent.normalized * Vector3.Distance(midPoint, points[changedControlPoint].Point);
101 points[changedControlPoint].
Point = midPoint + tangent;
108 int pointIndex = points.Length;
109 Array.Resize<
SplinePoint>(ref points, points.Length + 1);
110 SetPoint(pointIndex, point);
115 float totalDistance = normalizedDistance * (NumPoints - 1);
117 int point1Index = Mathf.FloorToInt(totalDistance);
118 point1Index -= (point1Index % 3);
119 float subDistance = (totalDistance - point1Index) / 3;
127 if (point1Index + 3 >= NumPoints)
129 return points[NumPoints - 1].
Point;
133 return points[0].
Point;
136 point2Index = point1Index + 1;
137 point3Index = point1Index + 2;
138 point4Index = point1Index + 3;
143 point2Index = (point1Index + 1) % (NumPoints - 1);
144 point3Index = (point1Index + 2) % (NumPoints - 1);
145 point4Index = (point1Index + 3) % (NumPoints - 1);
148 Vector3 point1 = points[point1Index].
Point;
149 Vector3 point2 = points[point2Index].
Point;
150 Vector3 point3 = points[point3Index].
Point;
151 Vector3 point4 = points[point4Index].
Point;
158 if (pointIndex < 0 || pointIndex >= points.Length)
160 throw new IndexOutOfRangeException();
163 if (loops && pointIndex == NumPoints - 1)
165 points[pointIndex] = points[0];
169 return points[pointIndex].
Point;
174 if (pointIndex < 0 || pointIndex >= points.Length)
176 throw new IndexOutOfRangeException();
179 if (loops && pointIndex == NumPoints - 1)
181 points[pointIndex] = points[0];
185 if (AlignControlPoints)
187 if (pointIndex % 3 == 0)
189 Vector3 delta = point - points[pointIndex].
Point;
194 points[1].
Point += delta;
195 points[NumPoints - 2].
Point += delta;
196 points[NumPoints - 1].
Point = point;
198 else if (pointIndex == NumPoints)
200 points[0].
Point = point;
201 points[1].
Point += delta;
202 points[pointIndex - 1].
Point += delta;
206 points[pointIndex - 1].
Point += delta;
207 points[pointIndex + 1].
Point += delta;
214 points[pointIndex - 1].
Point += delta;
216 if (pointIndex + 1 < points.Length)
218 points[pointIndex + 1].
Point += delta;
224 points[pointIndex].
Point = point;
226 ForceUpdateAlignment(pointIndex);
232 float arrayValueLength = 1f / points.Length;
233 int indexA = Mathf.FloorToInt(normalizedLength * points.Length);
234 if (indexA >= points.Length)
239 int indexB = indexA + 1;
240 if (indexB >= points.Length)
245 float blendAmount = (normalizedLength - (arrayValueLength * indexA)) / arrayValueLength;
246 Quaternion rotation = Quaternion.Lerp(points[indexA].Rotation, points[indexB].Rotation, blendAmount);
247 return rotation * transform.up;
255 Vector3 last = GetPoint(0f);
256 for (
int i = 1; i < 10; i++)
258 Vector3 current = GetPoint((
float)i / 10);
259 distance += Vector3.Distance(last, current);
266 public class CustomEditor : LineBaseEditor
268 private static bool editPositions =
true;
269 private static bool editRotations =
false;
270 private static List<SplinePoint> pointsList =
new List<SplinePoint>();
271 private static HashSet<int> overlappingPointIndexes =
new HashSet<int>();
273 private const float overlappingPointThreshold = 0.015f;
276 protected override void DrawCustomFooter()
278 base.DrawCustomFooter();
282 overlappingPointIndexes.Clear();
284 if (DrawSectionStart(line.name +
" Points",
"Point Editing"))
286 if (GUILayout.Button(
" + Add Points to Start"))
293 newPoints[1].
Point = newPoints[2].
Point - (direction * distance);
294 newPoints[0].
Point = newPoints[1].
Point - (direction * distance);
295 pointsList.AddRange(newPoints);
296 pointsList.AddRange(line.points);
297 line.points = pointsList.ToArray();
301 if (GUILayout.Button(
" - Remove Points From Start"))
305 pointsList.AddRange(line.points);
306 pointsList.RemoveAt(0);
307 pointsList.RemoveAt(0);
308 pointsList.RemoveAt(0);
309 line.points = pointsList.ToArray();
315 bool wideModeSetting =
UnityEditor.EditorGUIUtility.wideMode;
321 GUI.color = (editPositions ? defaultColor : disabledColor);
322 editPositions =
UnityEditor.EditorGUILayout.Toggle(
"Edit Positions", editPositions);
323 for (
int i = 0; i < line.points.Length; i++)
325 GUI.color = (i % 3 == 0) ? handleColorCircle : handleColorSquare;
328 GUI.color = Color.Lerp(GUI.color, defaultColor, 0.75f);
330 for (
int j = 0; j < line.points.Length; j++)
337 if (Vector3.Distance(line.points[j].
Point, line.points[i].
Point) < overlappingPointThreshold)
339 overlappingPointIndexes.Add(i);
340 overlappingPointIndexes.Add(j);
341 GUI.color = errorColor;
349 GUI.color = Color.Lerp(GUI.color, disabledColor, 0.75f);
350 UnityEditor.EditorGUILayout.Vector3Field(
string.Empty, line.points[i].
Point);
356 GUI.color = defaultColor;
358 editRotations =
UnityEditor.EditorGUILayout.Toggle(
"Edit Rotations", editRotations);
359 GUI.color = (editRotations ? defaultColor : disabledColor);
360 for (
int i = 0; i < line.points.Length; i++)
362 GUI.color = (i % 3 == 0) ? handleColorCircle : handleColorSquare;
365 GUI.color = Color.Lerp(GUI.color, defaultColor, 0.75f);
366 line.points[i].
Rotation = Quaternion.Euler(
UnityEditor.EditorGUILayout.Vector3Field(
string.Empty, line.points[i].
Rotation.eulerAngles));
370 GUI.color = Color.Lerp(GUI.color, disabledColor, 0.75f);
371 UnityEditor.EditorGUILayout.Vector3Field(
string.Empty, line.points[i].
Rotation.eulerAngles);
377 UnityEditor.EditorGUIUtility.wideMode = wideModeSetting;
379 GUI.color = defaultColor;
381 if (overlappingPointIndexes.Count > 0)
383 GUI.color = errorColor;
384 if (GUILayout.Button(
"Fix overlapping points"))
387 foreach (
int overlappoingPointIndex
in overlappingPointIndexes)
389 line.points[overlappoingPointIndex].
Point += (
UnityEngine.Random.onUnitSphere * overlappingPointThreshold * 2);
396 GUI.color = defaultColor;
397 if (GUILayout.Button(
" + Add Points To End"))
405 newPoints[1].
Point = newPoints[0].
Point + (direction * distance);
406 newPoints[2].
Point = newPoints[1].
Point + (direction * distance);
407 pointsList.AddRange(line.points);
408 pointsList.AddRange(newPoints);
409 line.points = pointsList.ToArray();
413 if (GUILayout.Button(
" - Remove Points From End"))
417 pointsList.AddRange(line.points);
418 pointsList.RemoveAt(pointsList.Count - 1);
419 pointsList.RemoveAt(pointsList.Count - 1);
420 pointsList.RemoveAt(pointsList.Count - 1);
421 line.points = pointsList.ToArray();
428 protected override void DrawCustomSceneGUI()
432 base.DrawCustomSceneGUI();