2D: Why does my player only move a tiny bit during point-and-click movement?

Hi everyone, absolute beginner here. I’m sorry because I know it’s a stupid question, but I can’t manage to find a solution. I want to make a 2d point and click movement script which adjusts to a grid. This is the script:

public class Movement : MonoBehaviour
{
    public int speed;
    Vector3 destination;

    private void Start()
    {
        speed = 3;
    }

    private void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            destination = new Vector3(Mathf.RoundToInt(mousePosition.x* 2) / 2,
                    Mathf.RoundToInt(mousePosition.y * 2) / 2,
                    transform.position.z); //the math is to adjust the position to the grid
            transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime);
        }
    }

The Player has an animator and a box collider 2d (I don’t think they matter); map borders have tile colliders and rigidbody (but the player doesn’t get there).
When I run it, the player only moves a tiny bit and doesn’t arrive where i clicked. If I set the speed to huge numbers (ex. 100000), the player moves and even dashes through colliders

You are using transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime); inside the if(Input.GetMouseButtonDown(0)). Lets say, you pressed the mouse button somewhere on screen, on first frame, your player will move a tiny bit, then on next frame the if(Input.GetMouseButtonDown(0)) will be false so the code inside if(Input.GetMouseButtonDown(0)) won’t get executed. That’s why your player is only moving a tiny bit. What you can do is use Coroutine inside the if(Input.GetMouseButtonDown(0))and pass the destination as parameter, so something like

if(Input.GetMouseButtonDown(0))
{
  //your code

  StartCoroutine(MovePlayer(destination));
}

IEnumerator MovePlayer(Vector3 destination)
{
  while(Vector3.Distance(transform.position, destination) < 0.01f)
  {
    transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime);
    yield return null;
  }
}

The problem is where that the player will only move while the MouseButton(0) is pressed. Given that it only moves at a *speed x Time.deltaTime* ratio, it can't reach its destination unless you (as you said) increase the speed value by a lot, making it just blink towards its destination.

You're doing it right by checking for the input in the Update method. But you should put the actual movement code into a loop that keeps moving the player until it reaches its destination. We'll keep it int eh Update method too for simplicity shake but more often than not is not the best way of doing it.

So it could be something like:

bool isMoving = false;

private void Update() {
    // Each time the user clicks, get the new destination
    if(Input.GetMouseButtonDown(0))
    {
         Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);

         destination = new Vector3(Mathf.RoundToInt(mousePosition.x* 2) / 2,
                 Mathf.RoundToInt(mousePosition.y * 2) / 2,
                 transform.position.z); 
                 //the math is to adjust the position to the grid

        // Let's add a bool to know if the player is moving or has reached its destination
        isMoving = true;
    }


    if(isMoving)
    {
        // Move our position a step closer to the target.
        float step =  speed * Time.deltaTime; // calculate distance to move
        
        // Actual movement
        transform.position = Vector3.MoveTowards(transform.position, target.position, step);

        // Check if the position of the player is close enough to its destination 
        if (Vector3.Distance(transform.position, destination) < 0.001f)
        {
            transform.position = destination;
            isMoving = false;
        }
    } }

So we added a *bool* that will be *true* when the player has a new destination that hasn't reached yet and it will turn *false* when it does. This way, the Update method will check every frame if the player should keep moving and move it accordingly. If it doesn't, it'll just ignore the movement code and the player will remain still until the user clicks on a new destination.

You can check [this same example in the documentation.][1]