Day 62 — Implementing Point and Click Movement in Unity
Hey and welcome!
In order for the game to recognise whereabouts we’re clicking we can make use of something called RayCasting. A ray is a 3D line that detects intersecting collisions, when we raycast we are casting out one of these rays which can be handy in several different scenarios.
If you’re curious as to what a 3D line is it just means that it’s a line that can be viewed in a 3D space like the lines on our main camera here:
If you were to draw out the rays and colour them white they would look pretty similar to the lines above. A real world use we would have for rays could be a first person shooter. If you’re wanting to keep track of bullets being fired off you can use rays to track where they’re heading and where they collide.
In terms of our game here though, we’re going to be using raycasting to cast a ray from our mouse position to the world position and use that information to detect where the ray impacts in the world. That will probably be quite a confusing explanation currently so let’s get started with our first script which will help put things into perspective.
Go ahead and create a new Scripts folder that you can store in the Game folder and the create a new C# script and call it Player. Open up the script in your preferred editor and then add this into it:
public Camera camera;void Update()
{
if (Input.GetMouseButtonDown(0) == true)
{
RaycastHit hit;
Ray ray = camera.ScreenPointToRay(Input.mousePosition);if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.point);
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = hit.point;
}
}
}
To start things off here we’re creating a public Camera variable called camera which will store the main camera so that we can use it later in the script. Next up in the void update we have an if statement with the condition Input.GetMouseButtonDown(0) == true which checks if the user has pressed the left click on their mouse. The int value that you pass into here determines whether it’s a left click or right click with 0 for left and 1 for right.
Inside the if statement itself we start things off by creating two local variables called hit and ray. RaycastHit is a structure that used to get information about a raycast we perform and Ray is the actual ray itself that’s getting cast. What we’re assigning to our ray variable is pretty important here. The camera.ScreenPointToRay part returns a ray that’s coming from our camera and passing through a screen point
A screen point refers to screen space and it’s defined in pixels so it can vary depending on the monitor. The bottom left of the screen is (0,0) and the top right is (pixelWidth, pixelHeight) with those values being whatever the max range of pixels the monitor can handle. The important part about all of this is that we’re passing in the position of the mouse that’s used to determine the whereabouts our ray touches down in the world space.
The above gif here shows off what this line of code does for us, as you can see here the yellow line (ray) is coming directly from the camera and touch down where I had clicked in the scene.
Lasty is our second if statement which runs if the ray we cast using ScreenPointToRay collides with anything. If it does then this statement takes in the positional value from our ray and outputs it into the hit variable using the keyword out. The out keyword is just used to force hit to output a value.
Inside the if statement we’re outputting the impact point data stored in hit into the console using hit.point and we’re then we’re then visualising where the impact point is by creating a cube which looks something like this:
Don’t forget to add the player script to our capsule and add the main camera to our Camera property! With an impact point set when we click anywhere in the game it’s now time to move the player towards that point. To do this we can work with the navmesh to use a built-in method for setting an object’s location. Let’s start off by creating a reference to that library by including using UnityEngine.AI at the top of the script.
With that done we can get a reference to our Nav Mesh Agent that we baked in the previous article by adding in this code:
private NavMeshAgent _agent;void Start ()
{
_agent = GetComponent<NavMeshAgent>();
}
You should be good and familiar with GetComponent these days. With that reference we can make use of it by replacing our code in the Physics.Raycast if statement with this:
_agent.SetDestination(hit.point);
SetDestination is that built-in method I mentioned earlier, we just pass in the info on the point of impact and the code does the rest!
Things are getting very exciting now, you’ll notice that the player clips through the objects in the game so we’ll be looking at fixing that in a future article.