Search Unity

How can I change the code so when the object reach the last waypoint it will move in reverse ?

Discussion in 'Scripting' started by Chocolade, Oct 27, 2020.

  1. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class MoveOnCurvedLine : MonoBehaviour
    7. {
    8.    public LineRenderer lineRenderer;
    9.    public GameObject objectToMove;
    10.    public float speed;
    11.    public bool go = false;
    12.    public bool moveToFirstPositionOnStart = false;
    13.  
    14.    private Vector3[] positions;
    15.    private Vector3[] pos;
    16.    private int index = 0;
    17.  
    18.    // Start is called before the first frame update
    19.    void Start()
    20.    {
    21.        pos = GetLinePointsInWorldSpace();
    22.  
    23.        if (moveToFirstPositionOnStart == true)
    24.        {
    25.            objectToMove.transform.position = pos[index];
    26.        }
    27.    }
    28.  
    29.    Vector3[] GetLinePointsInWorldSpace()
    30.    {
    31.        positions = new Vector3[lineRenderer.positionCount];
    32.        //Get the positions which are shown in the inspector
    33.        lineRenderer.GetPositions(positions);
    34.  
    35.  
    36.        //the points returned are in world space
    37.        return positions;
    38.    }
    39.  
    40.    // Update is called once per frame
    41.    void Update()
    42.    {
    43.        if (go == true)
    44.        {
    45.            Move();
    46.        }
    47.    }
    48.  
    49.    void Move()
    50.    {
    51.        Vector3 newPos = objectToMove.transform.position;
    52.        float distanceToTravel = speed * Time.deltaTime;
    53.  
    54.        bool stillTraveling = true;
    55.        while (stillTraveling)
    56.        {
    57.            Vector3 oldPos = newPos;
    58.            newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
    59.            distanceToTravel -= Vector3.Distance(newPos, oldPos);
    60.  
    61.            if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
    62.            {
    63.                index = (index + 1) % pos.Length;
    64.            }
    65.            else
    66.            {
    67.                stillTraveling = false;
    68.            }
    69.        }
    70.  
    71.        objectToMove.transform.position = newPos;
    72.    }
    73. }
    74.  
    Now when the object that move is reaching the last position he is moving to the first position and then moving over again forward over all the positions.

    but instead I want to make that when the object that move is reaching the last position that he will move in reverse on the positions back to the first position and then move forward to the last position and so on in this logic.

    I'm not sure what should I change to get what I want in the line :

    Code (csharp):
    1.  
    2. index = (index + 1) % pos.Length;
    3.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    I would just duplicate the first N-1 waypoints to the second half of the position array.

    So if the array originally contained these points:

    0, 1, 2, 3,


    Make a new larger array (larger by N - 1) and copy the points back in reverse order:

    0, 1, 2, 3, 2, 1, 0


    That way none of the other logic has to change.

    You could even make a
    public bool BiDirectional;
    argument to only conditionally loop it backwards like that.

    Alternately you could probably accomplish the same thing with Mathf.PingPong() but I would sooner dupe and reverse the points.
     
    Chocolade likes this.
  3. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    Can you show me please how to do it ? I messed it up.

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class MoveOnCurvedLine : MonoBehaviour
    7. {
    8.     public LineRenderer lineRenderer;
    9.     public GameObject objectToMove;
    10.     public float speed;
    11.     public bool go = false;
    12.     public bool moveToFirstPositionOnStart = false;
    13.  
    14.     private Vector3[] positions;
    15.     private Vector3[] pos;
    16.     private int index = 0;
    17.  
    18.     // Start is called before the first frame update
    19.     void Start()
    20.     {
    21.         pos = GetLinePointsInWorldSpace();
    22.  
    23.         if (moveToFirstPositionOnStart == true)
    24.         {
    25.             objectToMove.transform.position = pos[index];
    26.         }
    27.     }
    28.  
    29.     Vector3[] GetLinePointsInWorldSpace()
    30.     {
    31.         positions = new Vector3[lineRenderer.positionCount];
    32.         //Get the positions which are shown in the inspector
    33.         lineRenderer.GetPositions(positions);
    34.  
    35.  
    36.         //the points returned are in world space
    37.         return positions;
    38.     }
    39.  
    40.     // Update is called once per frame
    41.     void Update()
    42.     {
    43.         if (go == true)
    44.         {
    45.             Move();
    46.         }
    47.  
    48.         if (index == pos.Length - 1)
    49.         {
    50.             go = false;
    51.             MoveBack();
    52.         }
    53.     }
    54.  
    55.     void Move()
    56.     {
    57.         Vector3 newPos = objectToMove.transform.position;
    58.         float distanceToTravel = speed * Time.deltaTime;
    59.  
    60.         bool stillTraveling = true;
    61.         while (stillTraveling)
    62.         {
    63.             Vector3 oldPos = newPos;
    64.             newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
    65.             distanceToTravel -= Vector3.Distance(newPos, oldPos);
    66.  
    67.             if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
    68.             {
    69.                 index = (index + 1) % pos.Length;
    70.             }
    71.             else
    72.             {
    73.                 stillTraveling = false;
    74.             }
    75.         }
    76.  
    77.         objectToMove.transform.position = newPos;
    78.     }
    79.  
    80.     void MoveBack()
    81.     {
    82.         Vector3 newPos = objectToMove.transform.position;
    83.         float distanceToTravel = speed * Time.deltaTime;
    84.  
    85.         bool stillTraveling = true;
    86.         while (stillTraveling)
    87.         {
    88.             Vector3 oldPos = newPos;
    89.             newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
    90.             distanceToTravel -= Vector3.Distance(newPos, oldPos);
    91.  
    92.             if (newPos == pos[pos.Length - 1]) // Vector3 comparison is approximate so this is ok
    93.             {
    94.                 index = (index - 1) % pos.Length;
    95.             }
    96.             else
    97.             {
    98.                 stillTraveling = false;
    99.             }
    100.         }
    101.  
    102.         objectToMove.transform.position = newPos;
    103.     }
    104. }
    105.  
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    Low-level manipulation
    Example #1 arrays, create new (exclusive to arrays)
    Code (csharp):
    1. using System;
    2.  
    3. int[] BounceBackArray(int[] myArray) {
    4.   if(myArray == null) return null;
    5.   int len = myArray.Length;
    6.   if(len == 1) return new int[1] { myArray[0] };
    7.   if(len == 0) return new int[0];
    8.   int[] revArray = (int[])myArray.Clone();
    9.   Array.Reverse(revArray);
    10.  
    11.   int[] newArray = new int[2 * len - 1];
    12.   Array.Copy(myArray, 0, newArray, 0, len);
    13.   Array.Copy(revArray, 1, newArray, len, revArray.Length - 1);
    14.   return newArray;
    15. }
    Example #2 arrays, modify existing (exclusive to arrays)
    Code (csharp):
    1. using System;
    2.  
    3. void BounceBackArray(ref int[] myArray) {
    4.   if(myArray == null) return;
    5.   int len = myArray.Length;
    6.   if(len <= 1) return;
    7.   int[] revArray = (int[])myArray.Clone();
    8.   Array.Reverse(revArray);
    9.  
    10.   Array.Resize(ref myArray, 2 * len - 1);
    11.   Array.Copy(revArray, 1, myArray, len, revArray.Length - 1);
    12. }
    General-purpose mid-level algorithms
    Example #3 lists, create a new one (also applicable to arrays)
    Code (csharp):
    1. using System.Collections.Generic;
    2.  
    3. List<int> BounceBackList(List<int> myList) {
    4.   if(myList == null) return null;
    5.   if(myList.Count <= 1) return new List<int>(myList);
    6.   int size = 2 * myList.Count - 1;
    7.   List<int> newList = new List<int>(size);
    8.   for(int i = 0; i < size; i++) {
    9.     if(i < myList.Count) newList.Add(myList[i]);
    10.     else newList.Add(myList[size - i - 1]);
    11.   }
    12.   return newList;
    13. }
    Example #4 lists, modify existing (also applicable to arrays)
    Code (csharp):
    1. using System.Collections.Generic;
    2.  
    3. void BounceBackList(ref List<int> myList) {
    4.   if(myList == null) return;
    5.   int size = myList.Count;
    6.   if(size <= 1) return;
    7.   for(int i = 1; i < size; i++)
    8.     myList.Add(myList[size - i - 1]);
    9. }
    Tests
    Code (csharp):
    1. void test() {
    2.   int[] ary1 = new int[] { 0, 1, 2, 3, 8 };
    3.   int[] ary2 = BounceBackArray(ary1);
    4.   show(ary2); // 0, 1, 2, 3, 8, 3, 2, 1, 0
    5.  
    6.   BounceBackArray(ref ary1);
    7.   show(ary1); // 0, 1, 2, 3, 8, 3, 2, 1, 0
    8.  
    9.   List<int> list1 = new List<int>() { 5, 6, 7, 11 };
    10.   List<int> list2 = BounceBackList(list1);
    11.   show(list2); // 5, 6, 7, 11, 7, 6, 5
    12.  
    13.   BounceBackList(ref list1);
    14.   show(list1); // 5, 6, 7, 11, 7, 6, 5
    15. }
    16.  
    17. void show(IList<int> list) {
    18.   var sb = new System.Text.StringBuilder();
    19.   var len = list.Count;
    20.   for(int i = 0; i < len; i++) {
    21.     sb.Append(list[i].ToString());
    22.     if(i < len - 1) sb.Append(", ");
    23.   }
    24.   Debug.Log(sb.ToString());
    25. }
     
    Last edited: Oct 28, 2020
  5. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    I tried this :

    Code (csharp):
    1.    
    2.         using System;
    3.         using System.Collections;
    4.         using System.Collections.Generic;
    5.         using UnityEngine;
    6.        
    7.         public class MoveOnCurvedLine : MonoBehaviour
    8.         {
    9.             public LineRenderer lineRenderer;
    10.             public GameObject objectToMove;
    11.             public float speed;
    12.             public bool go = false;
    13.             public bool moveToFirstPositionOnStart = false;
    14.        
    15.             private Vector3[] positions;
    16.             private Vector3[] pos;
    17.             private int index = 0;
    18.             private bool isreverse = false;
    19.        
    20.             // Start is called before the first frame update
    21.             void Start()
    22.             {
    23.                 pos = GetLinePointsInWorldSpace();
    24.        
    25.                 if (moveToFirstPositionOnStart == true)
    26.                 {
    27.                     objectToMove.transform.position = pos[index];
    28.                 }
    29.             }
    30.        
    31.             Vector3[] GetLinePointsInWorldSpace()
    32.             {
    33.                 positions = new Vector3[lineRenderer.positionCount];
    34.                 //Get the positions which are shown in the inspector
    35.                 lineRenderer.GetPositions(positions);
    36.        
    37.        
    38.                 //the points returned are in world space
    39.                 return positions;
    40.             }
    41.        
    42.             // Update is called once per frame
    43.             void Update()
    44.             {
    45.                 if (go == true)
    46.                 {
    47.                     Move();
    48.                 }
    49.        
    50.                 if (index == pos.Length - 1)
    51.                 {
    52.                     System.Array.Reverse(pos);
    53.                     isreverse = true;
    54.                 }
    55.             }
    56.        
    57.             void Move()
    58.             {
    59.                 Vector3 newPos = objectToMove.transform.position;
    60.                 float distanceToTravel = speed * Time.deltaTime;
    61.        
    62.                 bool stillTraveling = true;
    63.                 while (stillTraveling)
    64.                 {
    65.                     Vector3 oldPos = newPos;
    66.                     newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
    67.                     distanceToTravel -= Vector3.Distance(newPos, oldPos);
    68.        
    69.                     if (isreverse)
    70.                     {
    71.                         if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
    72.                         {
    73.                             index --;// % pos.Length;
    74.                         }
    75.                         else
    76.                         {
    77.                             stillTraveling = false;
    78.                         }
    79.                     }
    80.                     else
    81.                     {
    82.                         if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
    83.                         {
    84.                             index = (index + 1) % pos.Length;
    85.                         }
    86.                         else
    87.                         {
    88.                             stillTraveling = false;
    89.                         }
    90.                     }
    91.                 }
    92.        
    93.                 objectToMove.transform.position = newPos;
    94.             }
    95.         }
    96.  
    And it's moving in reverse when it's getting to the last position but there is a problem :

    Each time it's getting to the last position the object to move is stuck and shaking like it's trying to move back to forward but stay in place and shaking and then after few seconds it's starting moving back in reverse. Why it happens?
     
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    That line is an old trick for:
    index++; if(index>=pos.length) index=0;
    . It's very sneaky. The percent sign is a modulo. It's the only "new" math computers have over regular math. It means to divide and take the _remainder_. 3%12 is 3 (3 goes into 12 0 times with 3 left over), 4%12 is 4, but 12%12 is 0 (12 goes into 12 1 time, with 0 left over). It's very, very sneaky, but most programmers have seen it and recognize it right away.

    Moving backwards is harder than wrapping around to 0. Suppose you just got to waypoint 5. Do you go up to 6, or down to 4? You need an extra variable to remember which way you were going. A way to do it using just IF's:
    Code (CSharp):
    1. bool goForward=true;
    2.  
    3. // when you hit a waypoint:
    4. if(goForward) {
    5.   bool atLastOne=index>=pos.length-1;
    6.   if(!atLastOne) index++;
    7.   else { index--; goForward=false; }
    8. }
    9. else { // going backwards:
    10.   bool atFirstOne=index<=0;
    11.   if(!atFirstOne) index--;
    12.   else { index++; goForward=true; }
    13. }
    There are other cleverer ways. For example start with int dir=+1;. dir is your "how to I change index" value. Go to the next waypoint with index+=dir;. When you get to the end, turn dir from +1 to -1. Now index+=dir will automatically subtract 1.
     
    Chocolade likes this.
  7. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933

    Working great. Thanks.