-1

Here's the code that I suspect is causing problems. MovePath() is only called once in the Start() function.

private void MovePath(Vector2[] path)
{
    foreach (var t in path)
    {
        while (location != t)
        {
            Move(t);
        }
    }
}

private void Move(Vector2 target)
{
    var position = (Vector2) transform.position;
    var direction= target - position;
    direction.Normalize();
    
    transform.right = (target - position) * -1;
    var endPosition = position + (direction * moveSpeed * Time.deltaTime);
    rb.MovePosition(endPosition);
    location = endPosition;
}

I'm interested as to why Unity hangs for me even though location could equal t eventually...

OJS05
  • 1
  • 1
  • 1
    You are going to want to put movement code in `Update` or look into [`Coroutines`](https://docs.unity3d.com/Manual/Coroutines.html) the reason is that you have effectively made an infinite loop. You also will not want to make direct comparisons of type `Vector2` due to floating-point precision. You will most likely want to use `Vector.Distance(location, t) <= EPSILON`, where EPSILON is some value close to 0. – TEEBQNE Sep 03 '21 at 02:50

2 Answers2

0

To clarify my comment, there are two main issues. The first being that movement should not be done outside of Update, a Coroutine, or any other equivalent. The reason for this is because normal functions are called and ran until completed. Update and Coroutines run in small increments over time, which is generally how movement should be done. With your current setup, the movement would all happen in one frame.

The second issue is your comparison. As a Vector2 is just two floats, there is a chance of floating point values never quit being equal. To fix this problem, instead of a direct comparison, you can compare the distance between two Vector2 values to a value close enough to 0, or what is called an epsilon value. In doing this, you assure that the value is close enough and can terminate your loop.

Combining all of this into an answer, I would advise you to use a Coroutine as it is similar to your current setup, just tweaked slightly to assure the movement happens over multiple frames. I would also recommend using Vector2.MoveTowards over the current MovePosition as MovePosition is generally placed in FixedUpdate as it is a physics-based function.

[SerializeField] private Vector2[] path;
[SerializeField] private float moveSpeed;
private Coroutine movePath = null;

private void Start()
{
    movePath = StartCoroutine(TraversePath(path));
}

private IEnumerator TraversePath(Vector2[] p)
{
    int pathIdx = 0;
    while (pathIdx < p.Length)
    {
        yield return StartCoroutine(MoveToTarget(p[pathIdx]));
        pathIdx++;
    }

    movePath = null;
}

private IEnumerator MoveToTarget(Vector2 target)
{
    while (!Mathf.Approximately(Vector2.Distance(target, transform.position), 0.0f))
    {
        transform.position = Vector2.MoveTowards(transform.position, target, moveSpeed * Time.deltaTime);
        yield return null;
    }

    transform.position = target;
}
TEEBQNE
  • 6,104
  • 3
  • 20
  • 37
-1

It is the code that is hanging because you never actually reach the target - you either end just before or skip over it - or it's a unity bug where it returns a very small value as a different instead of 0. You need to implement cutoffs.

// We can change this as needed
float distBuffer = 0.1f;

while ( Vector2.Distance(rb.position, t) < distBuffer){ ... }

Now the move function. We use Lerp so that we are sure we'll hit the location and not skip over it.

float speed = 5;

private void Move(Vector2 target)
{
    // Get the direction
    var dir = (target - (Vector2) transform.position).normalized;
    
    // Move the 
    Rigidbody.MovePosition (Vector3.Lerp (transform.position, transform.position + direction * Time.DeltaTime * speed, 1f));
    
}
CorrieJanse
  • 2,374
  • 1
  • 6
  • 23
  • Was not the downvoter, but this code would still not work as intended. I have not tested it, but using a `Lerp` outside of an incremental function most likely will still result in a freeze or crash as it is similar to an infinite loop. The `Time.deltaTime` is the time elapsed since the last frame, and inside of a closed `while` loop, no time will pass as it is stuck in the `while` trying to process the movement. Using the class declaration of `Rigidbody` will also not apply the motion to the component on the object. – TEEBQNE Sep 03 '21 at 03:25