Click to Move System in Unity

Richard Morgan
3 min readJan 5, 2023

Let’s write a simple script that will move an object to a clicked location like this:

Here’s the script that gets added to the player object:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClickToMove : MonoBehaviour
{
// Variable to store the speed at which the object should move
public float speed = 10f;
// Variable to store the target destination
public Vector3 _targetDestination;

// Start is called before the first frame update
void Start()
{
// Set the target destination to the object's starting position
_targetDestination = transform.position;
}

// Update is called once per frame
void Update()
{
// Check if the left mouse button was clicked
if (Input.GetMouseButtonDown(0))
{
// Create a ray from the main camera to the mouse position
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// Check if the ray hits an object on the "Floor" layer
if (Physics.Raycast(ray, out hit, 1000f, LayerMask.GetMask("Floor")))
{
// Set the target destination to the point where the ray hit the object
Vector3 target = hit.point;
// Set the y-position of the target to the object's current y-position
// This is to prevent the object from changing height when moving
target.y = transform.position.y;
_targetDestination = target;
// Rotate the object to face the target destination
transform.LookAt(target);
}
}
// Check if the distance between the object and the target destination is greater than 0.1
if (Vector3.Distance(transform.position, _targetDestination) > 0.1f)
{
// If so, move the object towards the target destination
MoveThePlayer();
}
}

// Method to move the object towards the target destination
void MoveThePlayer()
{
// Move the object towards the target destination at a speed of "speed" per second
transform.position = Vector3.MoveTowards(transform.position, _targetDestination, speed * Time.deltaTime);
}

}

Now our player will go wherever we click.

Just for fun, let’s do some optimization:

  1. Instead of using Physics.Raycast in the Update function, we could use a separate function to handle the raycasting and mouse input. This would reduce the number of calls to Physics.Raycast and make the code easier to read.
  2. Instead of checking the distance between the object and the target destination every frame, we could use a boolean variable to track whether the object has reached the target destination. This would prevent unnecessary calls to Vector3.Distance.
  3. We could also use a coroutine to move the object towards the target destination instead of using MoveThePlayer in the Update function. This would allow us to control the speed at which the object moves more accurately.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClickToMove : MonoBehaviour
{
// Variable to store the speed at which the object should move
public float speed = 10f;
// Variable to store the target destination
public Vector3 _targetDestination;
// Variable to track whether the object has reached the target destination
private bool _hasReachedDestination;

// Start is called before the first frame update
void Start()
{
// Set the target destination to the object's starting position
_targetDestination = transform.position;
}

// Update is called once per frame
void Update()
{
// Call the HandleInput function
HandleInput();
// Check if the object has reached the target destination
if (!_hasReachedDestination)
{
// If not, move the object towards the target destination
MoveThePlayer();
}
}

// Method to move the object towards the target destination
void MoveThePlayer()
{
// Move the object towards the target destination at a speed of "speed" per second
transform.position = Vector3.MoveTowards(transform.position, _targetDestination, speed * Time.deltaTime);
// Check if the object has reached the target destination
if (Vector3.Distance(transform.position, _targetDestination) <= 0.1f)
{
// If so, set _hasReachedDestination to true
_hasReachedDestination = true;
}
}

// Function to handle mouse input and raycasting
void HandleInput()
{
// Check if the left mouse button was clicked
if (Input.GetMouseButtonDown(0))
{
// Create a ray from the main camera to the mouse position
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// Check if the ray hits an object on the "Floor" layer
if (Physics.Raycast(ray, out hit, 1000f, LayerMask.GetMask("Floor")))
{
// Set the target destination to the point where the ray hit the object
Vector3 target = hit.point;
// Set the y-position of the target to the object's current y-position
// This is to prevent the object from changing height when moving
target.y = transform.position.y;
_targetDestination = target;
// Rotate the object to face the target destination
transform.LookAt(target);
// Set _hasReachedDestination to false
_hasReachedDestination = false;
}
}
}
}

Ah, that’s better!

--

--