Skip to content

Commit

Permalink
- added handle size field for adjusting the handle size in scene
Browse files Browse the repository at this point in the history
- fixed incorrect first index rotation/orientation
- fixed stop loopmode implementation in the MoveAlongPath script
  • Loading branch information
romifauzi committed May 25, 2022
1 parent bfc43f5 commit b5abd9d
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 45 deletions.
28 changes: 15 additions & 13 deletions Assets/PathTools/Scenes/PathToolsExample.unity
Original file line number Diff line number Diff line change
Expand Up @@ -158,22 +158,23 @@ MonoBehaviour:
rightHandle: {x: -0.28970897, y: 0.013729572, z: -3.5340805}
orientation: -90
tangentType: 0
- localPos: {x: 1.4542342, y: 0.013729572, z: 0.3277291}
leftHandle: {x: 1.237987, y: 0.013729572, z: -0.6486104}
rightHandle: {x: 1.6652508, y: 0.013729572, z: 1.2804526}
- localPos: {x: 1.4273251, y: 0.27377248, z: 0.3277291}
leftHandle: {x: 1.2110769, y: 0.27377248, z: -0.6486101}
rightHandle: {x: 1.6383429, y: 0.27377248, z: 1.2804527}
orientation: 90
tangentType: 0
- localPos: {x: -0.2224189, y: 0.013729572, z: 2.9288592}
leftHandle: {x: 2.0906916, y: 0.013729572, z: 3.5246074}
rightHandle: {x: -2.2515397, y: 0.013729572, z: 2.4062533}
- localPos: {x: -0.39892852, y: 0.013729572, z: 3.2549062}
leftHandle: {x: 1.6936592, y: 0.013729572, z: 3.6338682}
rightHandle: {x: -2.3432288, y: 0.013729572, z: 2.9027987}
orientation: 0
tangentType: 0
selectedId: 0
closeLoop: 1
showUpVector: 0
lastPos: {x: 1.4542342, y: 0.013729572, z: 0.3277291}
lastLeftHandlePos: {x: 1.237987, y: 0.013729572, z: -0.6486104}
lastRightHandlePos: {x: 1.6652508, y: 0.013729572, z: 1.2804526}
handleMulti: 0.1
closeLoop: 0
showUpVector: 1
lastPos: {x: 1.4273251, y: 0.27377248, z: 0.3277291}
lastLeftHandlePos: {x: 1.2110769, y: 0.27377248, z: -0.6486101}
lastRightHandlePos: {x: 1.6383429, y: 0.27377248, z: 1.2804527}
--- !u!4 &800040797
Transform:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -308,7 +309,8 @@ MonoBehaviour:
loopMode: 0
useCustomUpVector: 0
customUpVector: {x: 0, y: 1, z: 0}
distance: 0
distance: 9.30682
pathLength: 9.30682
--- !u!23 &1977854513
MeshRenderer:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -365,7 +367,7 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1977854510}
m_LocalRotation: {x: -0.6220584, y: 0.6220584, z: -0.3362193, w: 0.3362193}
m_LocalRotation: {x: -0.33422214, y: -0.3379994, z: 0.6231337, w: 0.6210929}
m_LocalPosition: {x: -2.1664882, y: 0.027459145, z: -1.6148556}
m_LocalScale: {x: 0.4, y: 0.4, z: 1}
m_Children: []
Expand Down
24 changes: 17 additions & 7 deletions Assets/PathTools/Scripts/Editor/PathScriptEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ public class PathScriptEditor : Editor
float pickSize = 1f;
float subPickSize = 0.3f;

SerializedProperty handleSize;

SelectedNode currentSelectedNode;

private void OnEnable()
{
source = (PathScript)target;
handleSize = serializedObject.FindProperty("handleMulti");
}

private void OnSceneGUI()
Expand All @@ -30,7 +33,7 @@ private void OnSceneGUI()
if (i == selectedId)
continue;

if (Handles.Button(nodePos, Quaternion.identity, 0.2f, HandleUtility.GetHandleSize(nodePos) * pickSize, Handles.SphereHandleCap))
if (Handles.Button(nodePos, Quaternion.identity, handleSize.floatValue, HandleUtility.GetHandleSize(nodePos) * pickSize, Handles.SphereHandleCap))
{
source.lastPos = source.Nodes[i].localPos;
source.lastLeftHandlePos = source.Nodes[i].leftHandle;
Expand All @@ -46,6 +49,8 @@ private void OnSceneGUI()

public override void OnInspectorGUI()
{
serializedObject.Update();

if (source.Nodes.Count == 0)
selectedId = -1;

Expand All @@ -60,12 +65,17 @@ public override void OnInspectorGUI()

source.closeLoop = EditorGUILayout.Toggle("Close Loop", source.closeLoop);
source.showUpVector = EditorGUILayout.Toggle("Show Orientation", source.showUpVector);

EditorGUILayout.PropertyField(handleSize, new GUIContent("Handle Size"));

EditorGUILayout.LabelField(string.Format("Path Length: {0}", source.PathDistance));

if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(source);
}

serializedObject.ApplyModifiedProperties();
}

void DrawNodeInspector(int id)
Expand Down Expand Up @@ -94,18 +104,18 @@ void DrawBezierControl(int id)
case SelectedNode.Main:
//show position handle for main node, show button for tangent nodes
source.Nodes[id].localPos = WorldToLocal(Handles.PositionHandle(LocalToWorld(source.Nodes[id].localPos), Quaternion.identity));
DrawNodeButton(source.Nodes[id].leftHandle, SelectedNode.LeftTangent, 0.1f, Color.red);
DrawNodeButton(source.Nodes[id].rightHandle, SelectedNode.RightTangent, 0.1f, Color.red);
DrawNodeButton(source.Nodes[id].leftHandle, SelectedNode.LeftTangent, handleSize.floatValue * 0.6f, Color.red);
DrawNodeButton(source.Nodes[id].rightHandle, SelectedNode.RightTangent, handleSize.floatValue * 0.6f, Color.red);
break;
case SelectedNode.LeftTangent:
source.Nodes[id].leftHandle = WorldToLocal(Handles.PositionHandle(LocalToWorld(source.Nodes[id].leftHandle), Quaternion.identity));
DrawNodeButton(source.Nodes[id].localPos, SelectedNode.Main, 0.2f, Color.green);
DrawNodeButton(source.Nodes[id].rightHandle, SelectedNode.RightTangent, 0.1f, Color.red);
DrawNodeButton(source.Nodes[id].localPos, SelectedNode.Main, handleSize.floatValue, Color.green);
DrawNodeButton(source.Nodes[id].rightHandle, SelectedNode.RightTangent, handleSize.floatValue * 0.6f, Color.red);
break;
case SelectedNode.RightTangent:
source.Nodes[id].rightHandle = WorldToLocal(Handles.PositionHandle(LocalToWorld(source.Nodes[id].rightHandle), Quaternion.identity));
DrawNodeButton(source.Nodes[id].localPos, SelectedNode.Main, 0.2f, Color.green);
DrawNodeButton(source.Nodes[id].leftHandle, SelectedNode.LeftTangent, 0.1f, Color.red);
DrawNodeButton(source.Nodes[id].localPos, SelectedNode.Main, handleSize.floatValue, Color.green);
DrawNodeButton(source.Nodes[id].leftHandle, SelectedNode.LeftTangent, handleSize.floatValue * 0.6f, Color.red);
break;
}

Expand Down
17 changes: 16 additions & 1 deletion Assets/PathTools/Scripts/MoveAlongPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ public class MoveAlongPath : MonoBehaviour

[Header("Debug")]
[SerializeField] float distance;
[SerializeField] float pathLength;

private float runtimeDistance;
private float speedDirection = 1f;

//only for loop mode stop, to stop update from running
private bool arrived;

private void Start()
{
runtimeDistance = 0f;
Expand All @@ -28,6 +32,9 @@ private void Start()
// Update is called once per frame
void Update()
{
if (arrived)
return;

runtimeDistance += speed * speedDirection * Time.deltaTime;

if (loopMode == LoopMode.PingPong)
Expand All @@ -39,13 +46,19 @@ void Update()
}
else if (loopMode == LoopMode.Stop)
{
runtimeDistance = Mathf.Clamp(runtimeDistance, 0f, path.PathDistance);
var adjustedDistance = path.PathDistance * 0.999f;

runtimeDistance = Mathf.Clamp(runtimeDistance, 0f, adjustedDistance);

if (runtimeDistance >= adjustedDistance)
arrived = true;
}
else if (loopMode == LoopMode.Loop)
{
runtimeDistance %= path.PathDistance;
}

Debug.Log(runtimeDistance);
transform.position = path.GetPositionAtDistance(runtimeDistance);
Quaternion targetRot = path.GetRotationAtDistance(runtimeDistance, useCustomUpVector ? customUpVector : path.GetUpVectorAtDistance(runtimeDistance));
transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime);
Expand All @@ -60,6 +73,8 @@ private void OnValidate()
transform.position = path.GetPositionAtDistance(distance);
Quaternion targetRot = path.GetRotationAtDistance(distance, path.GetUpVectorAtDistance(distance));
transform.rotation = targetRot;

pathLength = path.PathDistance;
}
#endif
}
Expand Down
87 changes: 63 additions & 24 deletions Assets/PathTools/Scripts/PathScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class PathScript : MonoBehaviour
#region VARIABLES
[SerializeField] private List<Node> nodes = new List<Node>();
[SerializeField] private int selectedId;
[SerializeField] private float handleMulti = 0.2f;
public bool closeLoop, showUpVector;

private const int CURVE_SEGMENT = 20;
Expand Down Expand Up @@ -53,11 +54,8 @@ List<Vector3> GetCurveNodes()
Vector3 p1 = (nodes[i].rightHandle);
Vector3 p2 = (nodes[i + 1].leftHandle);
Vector3 p3 = (nodes[i + 1].localPos);
for (int j = 0; j < CURVE_SEGMENT; j++)
{
float t = j / (float)CURVE_SEGMENT;
curvedNodes.Add(CalculateBezierPath(p0, p1, p2, p3, t));
}

Interpolate(ref curvedNodes, p0, p1, p2, p3, i);
}

if (closeLoop)
Expand All @@ -69,10 +67,21 @@ List<Vector3> GetCurveNodes()
Vector3 p2 = (nodes[0].leftHandle);
Vector3 p3 = (nodes[0].localPos);

for (int j = 0; j < CURVE_SEGMENT; j++)
Interpolate(ref curvedNodes, p0, p1, p2, p3, id);
}

void Interpolate(ref List<Vector3> refNode, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, int i)
{
int start = !closeLoop ? (i == 0 ? 0 : 1) : 0;
int endOffset = closeLoop ? -1 : 0;

for (int j = start; j <= CURVE_SEGMENT + endOffset; j++)
{
float t = j / (float)CURVE_SEGMENT;
curvedNodes.Add(CalculateBezierPath(p0, p1, p2, p3, t));

var point = CalculateBezierPath(p0, p1, p2, p3, t);

refNode.Add(point);
}
}

Expand All @@ -81,31 +90,36 @@ List<Vector3> GetCurveNodes()

List<float> GetOrientationAlongCurve()
{
List<float> orienationNodes = new List<float>();
List<float> orientationNodes = new List<float>();

for (int i = 0; i < nodes.Count - 1; i++)
{
for (int j = 0; j < CURVE_SEGMENT; j++)
{
float t = j / (float)CURVE_SEGMENT;

orienationNodes.Add(Mathf.Lerp(nodes[i].orientation, nodes[i + 1].orientation, t));
}
Interpolate(ref orientationNodes, nodes, i, i + 1);
}

if (closeLoop)
{
int id = nodes.Count - 1;

for (int j = 0; j < CURVE_SEGMENT; j++)
Interpolate(ref orientationNodes, nodes, id, 0);
}

void Interpolate(ref List<float> refOrientationNodes, List<Node> _nodes, int i, int next)
{
int start = !closeLoop ? (i == 0 ? 0 : 1) : 0;
int endOffset = closeLoop ? -1 : 0;

for (int j = start; j <= CURVE_SEGMENT + endOffset; j++)
{
float t = j / (float)CURVE_SEGMENT;

orienationNodes.Add(Mathf.Lerp(nodes[id].orientation, nodes[0].orientation, t));
var value = Mathf.Lerp(_nodes[i].orientation, _nodes[next].orientation, t);

refOrientationNodes.Add(value);
}
}

return orienationNodes;
return orientationNodes;
}

Vector3 LocalToWorld(Vector3 localPos)
Expand Down Expand Up @@ -135,6 +149,8 @@ private void GetPrecisePoint(float distance, int count, out int posIndex, out fl

//extract the decimals from the resulting index
precision = distanceToIndex - posIndex;

//Debug.Log($"index: {posIndex}, precision {precision}");
}

#endregion
Expand Down Expand Up @@ -174,14 +190,15 @@ public Vector3 GetPositionAtDistance(float distance)
bool lastPosInList = posIndex == curvedPositions.Count - 1;

//define the next index
int nextId = lastPosInList ? 0 : posIndex + 1;
int nextId = lastPosInList ? (!closeLoop ? posIndex : 0) : posIndex + 1;

if (lastPosInList && !closeLoop)
precision = 1f;
precision = 0f;

//get the precise position on curve at distance
pos = transform.TransformPoint(Vector3.Lerp(curvedPositions[posIndex], curvedPositions[nextId], precision));

//Debug.Log($"index: {posIndex}, precision {precision}");
return pos;
}

Expand All @@ -191,9 +208,13 @@ public Quaternion GetRotationAtDistance(float distance, Vector3 up)

GetPrecisePoint(distance, curvedPositions.Count, out int posIndex, out float precision);

int nextId = posIndex == curvedPositions.Count - 1 ? 0 : posIndex + 1;
//int nextId = posIndex == curvedPositions.Count - 1 ? 0 : posIndex + 1;
int nextId = posIndex == 0 ? (closeLoop ? curvedPositions.Count - 1 : 1) : posIndex - 1;

quat = Quaternion.LookRotation(curvedPositions[nextId] - curvedPositions[posIndex], up);
if (!closeLoop && posIndex == 0)
quat = Quaternion.LookRotation(curvedPositions[posIndex] - curvedPositions[nextId], up);
else
quat = Quaternion.LookRotation(curvedPositions[nextId] - curvedPositions[posIndex], up);

return quat;
}
Expand All @@ -206,9 +227,17 @@ public Quaternion GetRotationAtDistance(float distance)
public Vector3 GetUpVectorAtDistance(float distance)
{
GetPrecisePoint(distance, curvedPositions.Count, out int posIndex, out float precision);

Vector3 direction;

int nextId = posIndex == 0 ? (closeLoop ? curvedPositions.Count - 1 : 1) : posIndex - 1;

//draw point up with orientation influence
Vector3 direction = (curvedPositions[posIndex] - curvedPositions[posIndex == 0 ? (curvedPositions.Count - 1) : (posIndex - 1)]).normalized;
if (!closeLoop && posIndex == 0)
direction = (curvedPositions[nextId] - curvedPositions[posIndex]).normalized;
else
direction = (curvedPositions[posIndex] - curvedPositions[nextId]).normalized;

Vector3 finalDirection = Quaternion.AngleAxis(orientations[posIndex], direction) * Vector3.up;

return finalDirection;
Expand Down Expand Up @@ -241,10 +270,20 @@ private void OnDrawGizmos()
for (int i = 0; i < orientations.Count; i++)
{
//draw point up with orientation influence
Vector3 direction = (curvedPositions[i] - curvedPositions[i == 0 ? (curvedPositions.Count - 1) : (i - 1)]).normalized;
int nextId = i == 0 ? (closeLoop ? curvedPositions.Count - 1 : 1) : i - 1;
Vector3 direction;

//draw point up with orientation influence
if (!closeLoop && i == 0)
direction = (curvedPositions[nextId] - curvedPositions[i]).normalized;
else
direction = (curvedPositions[i] - curvedPositions[nextId]).normalized;

Vector3 finalDirection = Quaternion.AngleAxis(orientations[i], direction) * Vector3.up;
var worldPos = LocalToWorld(curvedPositions[i]);
Gizmos.color = Color.red;
Gizmos.DrawLine(LocalToWorld(curvedPositions[i]), LocalToWorld(curvedPositions[i]) + (finalDirection * 0.4f));
Gizmos.DrawLine(worldPos, worldPos + (finalDirection * 0.4f));
//UnityEditor.Handles.Label(worldPos + (finalDirection * 0.5f), i.ToString());
}
}
}
Expand Down

0 comments on commit b5abd9d

Please sign in to comment.