Search Unity

Question How should I update the linerenderer positions when changing one or more of the curved lines points?

Discussion in 'Scripting' started by shamenraze1988, Apr 13, 2021.

  1. shamenraze1988

    shamenraze1988

    Joined:
    Nov 24, 2020
    Posts:
    208
    A bit long and complicated but it's all connected.

    I packed the project into a rar file and it can be download at this link :

    https://1drv.ms/u/s!AtV2OUzEcRzrxXJZY16jrj1GQC1j?e=N0pbwY

    The main goal is move an object over linerenderer positions and very fast speed if needed.
    Depending on how much curved points lines there is there will be much more positions to move on.

    The movement part is working fine. The problem or what I want to do that is not working is when I drag in the scene window one of the curved points and change the line/s it should create new positions and update the positions in the linerenderer positions list but it's not and the object that move is keep moving on the old(original) positions.

    The Waypoints script :

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5. using UnityEngine;
    6.  
    7. public class Waypoints : MonoBehaviour
    8. {
    9.     public GameObject objToMove;
    10.     public LineRenderer lineRenderer;
    11.     public float speed;
    12.     public bool go = false;
    13.     public bool moveToFirstPositionOnStart = false;
    14.     public float rotSpeed;
    15.     public bool random = false;
    16.     public int currentCurvedLinePointIndex;
    17.  
    18.     private Vector3[] positions;
    19.     private Vector3[] pos;
    20.     private int index = 0;
    21.     private bool goForward = true;
    22.     private List<GameObject> curvedLinePoints = new List<GameObject>();
    23.     private int numofposbetweenpoints;
    24.     private bool getPositions = false;
    25.     int randomIndex;
    26.     int curvedPointsIndex;
    27.  
    28.     // Start is called before the first frame update
    29.     void Start()
    30.     {
    31.         curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
    32.  
    33.         if (curvedLinePoints != null && curvedLinePoints.Count > 0)
    34.         {
    35.            objToMove.transform.rotation = curvedLinePoints[1].transform.rotation;
    36.         }
    37.     }
    38.  
    39.     Vector3[] GetLinePointsInWorldSpace()
    40.     {
    41.         positions = new Vector3[lineRenderer.positionCount];
    42.         //Get the positions which are shown in the inspector
    43.         lineRenderer.GetPositions(positions);
    44.  
    45.  
    46.         //the points returned are in world space
    47.         return positions;
    48.     }
    49.  
    50.     // Update is called once per frame
    51.     void Update()
    52.     {
    53.         if (lineRenderer.positionCount > 0 && getPositions == false)
    54.         {
    55.             pos = GetLinePointsInWorldSpace();
    56.             numofposbetweenpoints = curvedLinePoints.Count;
    57.  
    58.             if (moveToFirstPositionOnStart == true)
    59.             {
    60.                 objToMove.transform.position = pos[index];
    61.             }
    62.  
    63.             getPositions = true;
    64.         }
    65.  
    66.         if (go == true && lineRenderer.positionCount > 0)
    67.         {
    68.             Move();
    69.         }
    70.  
    71.         var dist = Vector3.Distance(objToMove.transform.position, curvedLinePoints[curvedPointsIndex].transform.position);
    72.         if (dist < 0.1f)
    73.         {
    74.             if (curvedPointsIndex < curvedLinePoints.Count - 1)
    75.                 curvedPointsIndex++;
    76.  
    77.             currentCurvedLinePointIndex = curvedPointsIndex;
    78.         }
    79.     }
    80.  
    81.     int counter = 0;
    82.     int c = 1;
    83.     void Move()
    84.     {
    85.         Vector3 newPos = objToMove.transform.position;
    86.         float distanceToTravel = speed * Time.deltaTime;
    87.  
    88.         bool stillTraveling = true;
    89.         while (stillTraveling)
    90.         {
    91.             Vector3 oldPos = newPos;
    92.  
    93.             newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
    94.  
    95.             distanceToTravel -= Vector3.Distance(newPos, oldPos);
    96.             if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
    97.             {
    98.                 // when you hit a waypoint:
    99.                 if (goForward)
    100.                 {
    101.                     bool atLastOne = index >= pos.Length - 1;
    102.                     if (!atLastOne)
    103.                     {
    104.                         index++;
    105.                         counter++;
    106.                         if (counter == numofposbetweenpoints)
    107.                         {
    108.                             c++;
    109.  
    110.                             counter = 0;
    111.                         }
    112.                         if (c == curvedLinePoints.Count - 1)
    113.                         {
    114.                             c = 0;
    115.                         }
    116.                     }
    117.                     else { index--; goForward = false; }
    118.                 }
    119.                 else
    120.                 { // going backwards:
    121.                     bool atFirstOne = index <= 0;
    122.                     if (!atFirstOne)
    123.                     {
    124.                         index--;
    125.  
    126.                         counter++;
    127.                         if (counter == numofposbetweenpoints)
    128.                         {
    129.                             c++;
    130.  
    131.                             counter = 0;
    132.                         }
    133.                         if (c == curvedLinePoints.Count - 1)
    134.                         {
    135.                             c = 0;
    136.                         }
    137.                     }
    138.                     else { index++; goForward = true; }
    139.                 }
    140.             }
    141.             else
    142.             {
    143.                 stillTraveling = false;
    144.             }
    145.         }
    146.  
    147.         objToMove.transform.position = newPos;
    148.     }
    149. }
    150.  
    The generate line script. This create number of curved points and then create lines between the curved points. Each line is array of positions the object will move on :

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class GenerateLines : MonoBehaviour
    7. {
    8.     public GameObject linesWaypointsPrefab;
    9.     public int amountOfLines = 30;
    10.     public int minRandRange, maxRandRange;
    11.     public bool randomPositions = false;
    12.     public bool generateNewPositions = false;
    13.  
    14.     private List<Vector3> linesWaypoints = new List<Vector3>();
    15.     private Transform waypointsLinesParent;
    16.  
    17.     // Start is called before the first frame update
    18.     void Awake()
    19.     {
    20.         waypointsLinesParent = GameObject.Find("Curved Points").transform;
    21.  
    22.         if (generateNewPositions || (linesWaypoints.Count == 0 && amountOfLines > 0))
    23.         {
    24.             GenerateLinesWaypoints();
    25.         }
    26.     }
    27.  
    28.     // Update is called once per frame
    29.     void Update()
    30.     {
    31.  
    32.     }
    33.  
    34.     private void GenerateLinesWaypoints()
    35.     {
    36.         for (int i = 0; i < amountOfLines; i++)
    37.         {
    38.             if (randomPositions)
    39.             {
    40.                 var randPosX = UnityEngine.Random.Range(minRandRange, maxRandRange);
    41.                 var randPosY = UnityEngine.Random.Range(minRandRange, maxRandRange);
    42.                 var randPosZ = UnityEngine.Random.Range(minRandRange, maxRandRange);
    43.  
    44.                 if (linesWaypointsPrefab != null)
    45.                 {
    46.                     var LineWaypoint = Instantiate(linesWaypointsPrefab,
    47.                         new Vector3(randPosX, randPosY, randPosZ), Quaternion.identity, waypointsLinesParent);
    48.  
    49.                     LineWaypoint.name = "Curved Line Point";
    50.                     LineWaypoint.tag = "Curved Line Point";
    51.                 }
    52.             }
    53.             else
    54.             {
    55.                 if (linesWaypointsPrefab != null)
    56.                 {
    57.                     var LineWaypoint = Instantiate(linesWaypointsPrefab,
    58.                         new Vector3(i, i, i), Quaternion.identity, waypointsLinesParent);
    59.  
    60.                     LineWaypoint.name = "Curved Line Point";
    61.                     LineWaypoint.tag = "Curved Line Point";
    62.                 }
    63.             }
    64.         }
    65.     }
    66. }
    67.  
    Curved line renderer draw the lines :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. [RequireComponent(typeof(LineRenderer))]
    7. public class CurvedLineRenderer : MonoBehaviour
    8. {
    9.     //PUBLIC
    10.     public float lineSegmentSize = 0.15f;
    11.     public float lineWidth = 0.1f;
    12.     [Tooltip("Enable this to set a custom width for the line end")]
    13.     public bool useCustomEndWidth = false;
    14.     [Tooltip("Custom width for the line end")]
    15.     public float endWidth = 0.1f;
    16.     [Header("Gizmos")]
    17.     public bool showGizmos = true;
    18.     public float gizmoSize = 0.1f;
    19.     public Color gizmoColor = new Color(1, 0, 0, 0.5f);
    20.     //PRIVATE
    21.     private CurvedLinePoint[] linePoints = new CurvedLinePoint[0];
    22.     private Vector3[] linePositions = new Vector3[0];
    23.     private Vector3[] linePositionsOld = new Vector3[0];
    24.  
    25.     private void Start()
    26.     {
    27.      
    28.     }
    29.  
    30.     // Update is called once per frame
    31.     public void Update()
    32.     {
    33.         GetPoints();
    34.         SetPointsToLine();
    35.     }
    36.  
    37.     public void GetPoints()
    38.     {
    39.         //find curved points in children
    40.         linePoints = this.GetComponentsInChildren<CurvedLinePoint>();
    41.  
    42.         //add positions
    43.         linePositions = new Vector3[linePoints.Length];
    44.         for (int i = 0; i < linePoints.Length; i++)
    45.         {
    46.             linePositions[i] = linePoints[i].transform.position;
    47.         }
    48.     }
    49.  
    50.     public void SetPointsToLine()
    51.     {
    52.         //create old positions if they dont match
    53.         if (linePositionsOld.Length != linePositions.Length)
    54.         {
    55.             linePositionsOld = new Vector3[linePositions.Length];
    56.         }
    57.  
    58.         //check if line points have moved
    59.         bool moved = false;
    60.         for (int i = 0; i < linePositions.Length; i++)
    61.         {
    62.             //compare
    63.             if (linePositions[i] != linePositionsOld[i])
    64.             {
    65.                 moved = true;
    66.             }
    67.         }
    68.  
    69.         //update if moved
    70.         if (moved == true)
    71.         {
    72.             LineRenderer line = this.GetComponent<LineRenderer>();
    73.  
    74.             //get smoothed values
    75.             Vector3[] smoothedPoints = LineSmoother.SmoothLine(linePositions, lineSegmentSize);
    76.  
    77.             //set line settings
    78.             line.positionCount = smoothedPoints.Length;
    79.             line.SetPositions(smoothedPoints);
    80.             line.startWidth = lineWidth;
    81.             line.endWidth = useCustomEndWidth ? endWidth : lineWidth;
    82.         }
    83.     }
    84.  
    85.     void OnDrawGizmosSelected()
    86.     {
    87.         Update();
    88.     }
    89.  
    90.     void OnDrawGizmos()
    91.     {
    92.         if (linePoints.Length == 0)
    93.         {
    94.             GetPoints();
    95.         }
    96.  
    97.         //settings for gizmos
    98.         foreach (CurvedLinePoint linePoint in linePoints)
    99.         {
    100.             linePoint.showGizmo = showGizmos;
    101.             linePoint.gizmoSize = gizmoSize;
    102.             linePoint.gizmoColor = gizmoColor;
    103.         }
    104.     }
    105. }
    106.  
    Curved line point this script is attached to each created curved line point object :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEditor;
    5.  
    6. [ExecuteInEditMode]
    7. public class CurvedLinePoint : MonoBehaviour
    8. {
    9.     [HideInInspector] public bool showGizmo = true;
    10.     [HideInInspector] public float gizmoSize = 0.1f;
    11.     [HideInInspector] public Color gizmoColor = new Color(1, 0, 0, 0.5f);
    12.  
    13.     void OnDrawGizmos()
    14.     {
    15.         if (showGizmo == true)
    16.         {
    17.             Gizmos.color = gizmoColor;
    18.  
    19.             Gizmos.DrawSphere(this.transform.position, gizmoSize);
    20.         }
    21.     }
    22.  
    23.     //update parent line when this point moved
    24.     void OnDrawGizmosSelected()
    25.     {
    26.  
    27.     }
    28. }
    29.  
    Last Line Smoother :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class LineSmoother : MonoBehaviour
    7. {
    8.     public static Vector3[] SmoothLine(Vector3[] inputPoints, float segmentSize)
    9.     {
    10.         //create curves
    11.         AnimationCurve curveX = new AnimationCurve();
    12.         AnimationCurve curveY = new AnimationCurve();
    13.         AnimationCurve curveZ = new AnimationCurve();
    14.  
    15.         //create keyframe sets
    16.         Keyframe[] keysX = new Keyframe[inputPoints.Length];
    17.         Keyframe[] keysY = new Keyframe[inputPoints.Length];
    18.         Keyframe[] keysZ = new Keyframe[inputPoints.Length];
    19.  
    20.         //set keyframes
    21.         for (int i = 0; i < inputPoints.Length; i++)
    22.         {
    23.             keysX[i] = new Keyframe(i, inputPoints[i].x);
    24.             keysY[i] = new Keyframe(i, inputPoints[i].y);
    25.             keysZ[i] = new Keyframe(i, inputPoints[i].z);
    26.         }
    27.  
    28.         //apply keyframes to curves
    29.         curveX.keys = keysX;
    30.         curveY.keys = keysY;
    31.         curveZ.keys = keysZ;
    32.  
    33.         //smooth curve tangents
    34.         for (int i = 0; i < inputPoints.Length; i++)
    35.         {
    36.             curveX.SmoothTangents(i, 0);
    37.             curveY.SmoothTangents(i, 0);
    38.             curveZ.SmoothTangents(i, 0);
    39.         }
    40.  
    41.         //list to write smoothed values to
    42.         List<Vector3> lineSegments = new List<Vector3>();
    43.  
    44.         //find segments in each section
    45.         for (int i = 0; i < inputPoints.Length; i++)
    46.         {
    47.             //add first point
    48.             lineSegments.Add(inputPoints[i]);
    49.  
    50.             //make sure within range of array
    51.             if (i + 1 < inputPoints.Length)
    52.             {
    53.                 //find distance to next point
    54.                 float distanceToNext = Vector3.Distance(inputPoints[i], inputPoints[i + 1]);
    55.  
    56.                 //number of segments
    57.                 int segments = (int)(distanceToNext / segmentSize);
    58.  
    59.                 //add segments
    60.                 for (int s = 1; s < segments; s++)
    61.                 {
    62.                     //interpolated time on curve
    63.                     float time = ((float)s / (float)segments) + (float)i;
    64.  
    65.                     //sample curves to find smoothed position
    66.                     Vector3 newSegment = new Vector3(curveX.Evaluate(time), curveY.Evaluate(time), curveZ.Evaluate(time));
    67.  
    68.                     //add to list
    69.                     lineSegments.Add(newSegment);
    70.                 }
    71.             }
    72.         }
    73.  
    74.         return lineSegments.ToArray();
    75.     }
    76.  
    77. }
    78.  
    I packed the project into a rar file and it can be download at this link :

    https://1drv.ms/u/s!AtV2OUzEcRzrxXJZY16jrj1GQC1j?e=N0pbwY

    Some screenshots to explain :



    Now I drag one of the Cubes( Curved Line point )

    I dragged and moved the third Curved Line Point cube and when dragging it it's also changing the curved lines and change the positions of this lines more positions and in different positions.

    but the object that move over the lines positions is still moving on the old lines positions when the Curved Line Point was like in the first screenshot. It's not updating the LineRenderer positions I think.



    In the second screenshot in the scene view window on the top left you can see the cube on the left that cube I dragged.

    I think the problem is somewhere in the CurvedLineRenderer script. The script should update the linerenderer if I'm moving one or more of the Curved Line Point/s (The Cubes) but it's not.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    That's a lot to debug all at once. I suggest you simplify it to a single line renderer with 2 points, and get that working first.

    Isolate whether the issue is getting the right input from the mouse and converting it to movement distance in the LineRenderer's local space, or whether the problem is modifying the points themselves.
     
    shamenraze1988 likes this.