Unity crashes on event of specific code

I am working right now on the movement in a sort of turn-based game and am almost done configuring it,
I have this code, but I want something more complex so I could see the movement occur instead of the player just jumping to the position he needs:

rb.MovePosition(Vector3.MoveTowards(Player.transform.position,BattleGrid[2,1].position,200f));

it works, but I want to see the movement occur and smoothly, so I made this code to replace the previous code:

float sqrRemainingDistance = (Player.transform.position - BattleGrid[2,1].position).sqrMagnitude;
while(sqrRemainingDistance > 0)    		{
			Vector3 newPostion = Vector3.MoveTowards(rb.position, BattleGrid[2,1].position, inverseMoveTime * Time.deltaTime);
			rb.MovePosition (newPostion);
			sqrRemainingDistance = (Player.transform.position - BattleGrid[2,1].position).sqrMagnitude;

The issue is, this code makes the entire unity freeze up while playing, just when I do the thing that activates this code (or the previous code when I tried earlier).

There isn’t any error or warning popping up…
Does anyone know why this code makes the unity freeze up???

Problem is, your While loop never finishes.

Explanation why: Distance between two points, which is your distance, is never less than zero. Your “destination” is never precisely hit. Suppose your player is at one frame 0.1 distance from destination, and it moves at 0.07 units per frame.

Next frame he will be 0.03 units from the destination.

Next frame he will not be -0.06 units away. He will be 0.06 units away. Distance is never negative.

How to solve this:
Idea #1: Within the code that initiates the move command (a click or some other input, I assume), aside from starting the loop that moves the player, also first remember the initial distance the player has to travel.

Then, within the loop that moves the player, keep track of distance traveled so far. Once the distance traveled so far is equal or larger than initial distance that needed traversing, stop the player.

Idea #2: This is a bit quicker but less robust solution:
Instead of checking if sqrRemainingDistance is larger than zero, simply check if it’s larger than some fine tuned value. For example, move if distance is > 0.5, or such.

Additional problem: Even if your While loop were to finish normally, you would STILL see the player teleport to the destination.

This is because the Render of the scene happens once per frame, once all scripts have finished their execution. You have calculated and moved your player the entire distance within one While loop that executes fully within that one frame.

Instead of While loop, simply use the Update function of your script. This function executes one per frame. So, move your code from our while loop, into the Update loop (without While or other own loops). That way, each frame (each Update pass) your player will move for some small distance.

Code example

public Vector3 playerDestination;
public bool NeedsTravelling;

//[...]
//At the event that starts to move the player:
playerDestination = positionOnYourGridThatYouNeedToMoveTo;
NeedsTravelling = true;

//[...]

public void Update()
{
   if (NeedsTravelling)
  {
      Vector3 actualDistance = playerDestination - Player.transform.position;

      if (actualDistance.sqrMagnitude > 0.5)
      {  //Note: You will need to calibrate the Speed value, since it's used differently now, it will have to be some small value such as 0.01 or so I assume.
         actualDistance.Normalize();
          Player.transform.position += actualDistance * speed;
      }
      else
      {  //If we're close enough, do not travel anymore:
         NeedsTravelling = false;
      }
  }
}

I’m not an expert on explaining things, and my english is not great, but i will try to explain it :slight_smile:

If you do this in a while loop, it wants to do this in that one frame it starts in. And the code only continuous when the sqrRemainingDistance == 0. This will loop infinite (can’t explain why).

You can try to use this:
Vector3 newPosition = Vector3.Lerp(rb.position, BattleGrid[2, 1].position, Time.deltaTime * speed);
rb.position = newPosition;

Then you just check with an if statement if the rb.position == BattleGrid[2, 1], and if that is correct, you can continu with other stuff