Search Unity

Resolved Move something to a random position on a plane

Discussion in 'Scripting' started by jlorenzi, May 27, 2022.

  1. jlorenzi

    jlorenzi

    Joined:
    May 2, 2021
    Posts:
    292
    I'm trying to smoothly move something from point to point on a plane but my current code produces extremely jittery movement, and the cube I'm moving moves off the platform as well.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Floppa : MonoBehaviour
    6. {
    7.     public float maxWalkTime = 3.0f;
    8.     public float minWalkTime = 0.0f;
    9.     public Transform floor;
    10.     public float moveSpeed = 4;
    11.  
    12.     float nextWalkTime;
    13.     bool canMove;
    14.  
    15.     void Update()
    16.     {
    17.         if ( Time.time > nextWalkTime && !canMove )
    18.         {
    19.             canMove = true;
    20.         }
    21.  
    22.         if ( canMove )
    23.         {
    24.             Vector3 currentPos = transform.position;
    25.             Vector3 nextPos;
    26.  
    27.             float x = Random.Range( -floor.localScale.x / 2, floor.localScale.x / 2 );
    28.             float z = Random.Range( -floor.localScale.z / 2, floor.localScale.z / 2 );
    29.  
    30.             nextPos = floor.position + new Vector3(x, 0.68f, z);
    31.        
    32.             if ( currentPos.sqrMagnitude != nextPos.sqrMagnitude )
    33.             {
    34.                 transform.position = Vector3.Lerp(currentPos, nextPos, Time.deltaTime * moveSpeed);
    35.             }
    36.  
    37.             else
    38.             {
    39.                 nextWalkTime = Time.time + Random.Range(minWalkTime, maxWalkTime);
    40.  
    41.                 canMove = false;
    42.             }
    43.         }
    44.     }
    45. }
    46.  
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,981
    You want the calculation of your new random position inside the first if statement, so it is only calculated once. "nextPos" should be a member variable, declared in the class, so it can actually remember the position for longer than a single frame. Finally the way you use lerp would not be a linear motion but a decelerated motion that is very fast at the beginning and slows down at the end. That's because you use the current position as start position. Lerp moves from the given start towards the given target by the provided "percentage" (value between 0 and 1). Initially the distance between start and end is large, so if you move for example 5 percent (0.05) of a distance of 100 units, you would move 5 units in a step. As you get closer to the end, say the distance is only 10 units now, we still only move 5% towards the end which is now only 0.5 units.

    You should either use MoveTowards which does expect the current position and the end position as parameters as well as a delta how many units it should move in this frame. So it actualy expects a speed. If you want to use Lerp you usually need a timer that goes from 0 to 1. However this wouldn't make much sense in this case as the actual move speed would vary depending on the distance as the travel time would be constant for each movement.

    So you probably want something like this:
    Code (CSharp):
    1.  public float maxWalkTime = 3.0f;
    2.     public float minWalkTime = 0.0f;
    3.     public float moveSpeed = 4;
    4.     public Transform floor;
    5.     float nextWalkTime;
    6.     bool canMove;
    7.     Vector3 nextPos;
    8.     void Update()
    9.     {
    10.         if ( Time.time > nextWalkTime && !canMove )
    11.         {
    12.             float x = Random.Range( -floor.localScale.x / 2, floor.localScale.x / 2 );
    13.             float z = Random.Range( -floor.localScale.z / 2, floor.localScale.z / 2 );
    14.             nextPos = floor.position + new Vector3(x, 0.68f, z);
    15.             canMove = true;
    16.         }
    17.         if ( canMove )
    18.         {
    19.             Vector3 currentPos = transform.position;
    20.             if ( currentPos.sqrMagnitude != nextPos.sqrMagnitude )
    21.             {
    22.                 transform.position = Vector3.MoveTowards(currentPos, nextPos, Time.deltaTime * moveSpeed);
    23.             }
    24.             else
    25.             {
    26.                 nextWalkTime = Time.time + Random.Range(minWalkTime, maxWalkTime);
    27.                 canMove = false;
    28.             }
    29.         }
    30.     }

    To debug the target position you can add this method to show you the next position that the object is moving towards
    Code (CSharp):
    1.     void OnDrawGizmos()
    2.     {
    3.         Gizmos.color = Color.yellow;
    4.         Gizmos.DrawSphere(nextPos, 1);
    5.         Gizmos.DrawLine(transform.position, nextPos);
    6.     }
    Gizmos are only drawn inside the editor. Instead of
    OnDrawGizmos
    you can also use
    OnDrawGizmosSelected
    instead. This will only show the gizmos when the object is selected in the editor.
     
    jlorenzi likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,674
    While I'm sure Bunny's code above is awesome and buttery, you can always just use a tweener like LeanTween or DOTween or iTween to get out of writing and maintaining all this fiddly code. :)
     
    Bunny83 likes this.