Iterate on the player controller
Tutorial
·
foundational
·
+10XP
·
30 mins
·
(8)
Unity Technologies

This tutorial will guide you through integrating mouse controls into your game, allowing the player object to move towards a mouse click or touch input, including using layers to limit where the player can move. Through the process, you will also learn about the importance of flexibility in game controls for enhanced user interaction.
Languages available:
1. Overview
When it comes to developing games, flexibility in user interaction is key. You've used a keyboard-based control scheme for the player up to this point, but what if you wanted to try something different?
In this tutorial, you'll learn to use ray casts to move your player object towards a mouse click or touch input.
2. Create a ray from the camera to the mouse position
Our goal is to use rays to detect a spot in the play area where the player clicked and then move the player towards that target position. A ray is an infinite line starting at a specific point and going off in some direction. Rays are often used in games to shoot bullets, detect proximity, or, as we'll do here, detect mouse clicks.
To create a ray from the camera to the mouse position, follow these instructions:
1. Open the PlayerController script.
- We will add all of the functionality inside this script, allowing you to control the player with the mouse or with the keyboard. If you don’t like the mouse controls, you can always remove it later.
2. Log when the mouse is clicked.
- Add the following code to your new script.
With this code, the message "Mouse Clicked" will appear in the Console window whenever the left mouse button is pressed.
This code uses the Update() function instead of FixedUpdate() because the user can click the screen at any moment and the Update function runs every frame. FixedUpdate is synced with the game's physics system, which operates on a fixed time-step, so may not run every frame. By checking for input in Update, you ensure that even brief key presses or mouse clicks aren't missed between physics updates. The Update function is ideal for capturing fast, frame-dependent changes like user input.
Debug.Log statements are primarily used for debugging and providing real-time information during development. They are useful for identifying and resolving issues in your code. However, excessive use can clutter the console and slightly impact performance, so it's best to remove them for the final game release.
3. Test the Debug.Log statement.
Run your game and watch the Console window - you should see "Mouse Clicked" logged every frame that the mouse button is held down.
4. Collapse identical entries.
- Select Collapse at the top of the Console window.
This will group any identical commands into a single line and indicate with a number on the right how many times that same message was logged. This is very helpful for keeping your Console window tidy.

5. Cast a ray from the camera to the mouse position.
- Delete the Debug.Log statement you just added — you don’t need it anymore.
- Add the following code where the Debug.Log statement was, then test your game again:
This line of code creates a Ray GameObject that extends from the camera's position through a screen point. Let's break it down:
- Ray ray: This line declares a new variable ray of type Ray. It is used in Unity to detect collisions, among other things.
- Camera.main: This line refers to the main camera in your Unity scene. This is typically the camera tagged as the "MainCamera" in your scene, which is the camera used for rendering what the player sees in the game. If there are multiple cameras, Unity uses the first enabled camera it finds.
- ScreenPointToRay(Input.mousePosition): This function takes a position on the screen and transforms it into a ray from the camera. Here, Input.mousePosition is the position of the mouse cursor, measured in pixels from the bottom-left of the screen. ScreenPointToRay translates this 2D screen position into a 3D ray that extends into the world from the camera.
- Debug.Log(ray);: This line will log the origin and direction of the ray in the console. This can be useful for debugging, as you can verify that the ray is being cast as expected.
Test your game now. You'll see each ray's origin and direction logged in the Console window when you click.

6. Draw the ray.
- Delete the previous Debug.Log statement — you don’t need it anymore.
- Add the following code where the Debug.Log statement was, then test your game again:
This line of code is used to visualize a ray in the Unity Editor's Scene view. It will draw a ray starting from the origin point of the ray (ray.origin) extending along the ray's direction (ray.direction) for a specified length (multiplied by 20 in this case), and it will be colored yellow. Feel free to change the “yellow” to another color option.
Run your game again, with both the Game view and Scene view open. Now, whenever you click, you'll see a yellow ray in the Scene view from the camera to the click position.
Important: You must have Gizmos enabled in the Scene view to be able to visualize the rays.
3. Move the player towards the mouse
Now that you have the ray functioning as expected, you can use it to set the player’s target position and move the player towards that position.
First, we'll need to add variables for the player’s target position and a boolean to track if the player is moving. To do this, follow these instructions:
1. Add targetPos and isMoving variables.
- Declare these at the top of your script:
Adding [SerializeField] before a private variable makes that variable visible in the Inspector window while keeping its access restricted to within its class in the scripts. This is often done to allow designers and other team members to easily modify or view the values of certain variables from the Unity Editor without exposing the variable to potential unwanted access or modifications from other scripts.
2. Detect hit point and set the variables.
- Add the following code below the debug.DrawRay call in the Update function:
At a high level, this code uses a raycast to detect if the mouse has clicked on an object in the scene. If an object is hit, it sets a target position for player movement and turns on a flag for movement (isMoving = true);
Here’s a more detailed explanation of this code:
- RaycastHit stores info on a raycast's point of contact with an object, including its location, orientation, distance from origin, and the collider impacted.
- Physics.Raycast sends a ray into the scene from the origin point in the direction specified by the ray object. It returns true if the ray intersects with a collider, otherwise it returns false.
- The out keyword specifies that hit is an output variable. If the raycast hits an object, hit will be filled with the data about the collider the raycast hit. If the raycast does not hit any colliders, hit will be left unchanged.
- If the raycast hits an object, the point where the raycast hit is saved in targetPos. The hit.point property of a RaycastHit is a Vector3 that represents the exact point in world space where the raycast hit the object.
- The boolean isMoving is set to true, which means the player should now start moving towards the targetPos. The Player won’t actually do that yet since you haven’t programmed it, but you will use that variable to determine when the player should or shouldn’t move in the next step.
3. Stop moving when the mouse is not clicked.
- Add the following code after the entire if-statement checking when the mouse is clicked:
This code uses an else statement to check if the left mouse button is no longer held down to set isMoving to false, since we don’t want the player moving when the mouse is released.
4. Test your game.
- Test your game and keep the PlayerController component visible to monitor the isMoving variable.
- Notice that isMoving becomes true when you click and false when you release.
4. Move the player towards the target position
You now have all the data you’ll need to move the player:
- The isMoving variable will tell the player when to move.
- The targetPos variable will tell the player where to move.
Now all you need to do is actually move the player where and when it should move. To do this, follow these instructions:
1. Move the player.
- Add the following code to the bottom of the FixedUpdate function:
- In the FixedUpdate() method here, it first checks whether the player is supposed to be moving (isMoving). If yes, it calculates the direction — this is the straight path from where the player is now (rb.position) to the place we clicked (targetPos).
- But this direction vector can be big, which would make the player go flying, so we need to make it simpler — or normalize it. The direction.Normalize(); line converts the direction vector into a unit vector, ensuring its magnitude is 1 and maintaining only the direction information.
- Once you have the right direction, you then tell the player's Rigidbody (its physical component) to add a push or force towards that direction. The speed variable controls how big this push is, meaning how fast the player moves.
2. Test the player movement.
- Run the game — the player should move towards the mouse when it’s clicked!
3. Stop moving when the player reaches the mouse.
- Add the following code before the final curly bracket of the FixedUpdate function:
4. Test the updated movement.
- Run the game — the player should now stop moving when it’s close enough to the mouse.
- You might notice a problem: what happens if you click on a moving platform — the ball could end up floating in the air!
5. Control the ray cast with layers
In Unity, layers are a method of separating game objects in different categories. They're a kind of tagging system that allows you to create groups of objects for different purposes.
In your project, you’ll use layers to control where the player can move. By assigning just the ground-related objects to a Ground layer, you can tell the ray cast to specifically look for that layer. When a user clicks on something on that layer, the player will move. If the user clicks on anything not in the Ground layer, like a platform or outside the play area, the ray cast ignores it, and the player won’t move.
To control the ray cast with layers, follow these instructions:
1. Add a new Ground layer.
- If you don't have a Ground layer yet, create one by navigating to Layers > Edit Layers and adding a new layer in one of the empty slots.

2. Add ground objects to the Ground layer.
- Open the Layer dropdown at the top of the Inspector window and select your ground object to assign it to the Ground layer. You can also add any ramps you have to this layer.

3. Check if the ray hits the ground.
- Add the following if-statement around code that assigns the targetPos and isMoving variables within the Physics.Raycast if-statement:
This line of code checks if the object that your ray cast hits belongs to the Ground layer. If the object does belong to the Ground layer, it executes the code inside the if-statement.
4. Test the game.
The player should now only respond if you select an object assigned to the Ground layer.
6. Choose your controls
Now, your game has dual controls: the player can be controlled with the keyboard or with the mouse. Having multiple control schemes increases the accessibility of your game, since some players might find it difficult to use a keyboard or a mouse.
If you’d like to return to the original keyboard controls and remove the mouse controls entirely, all you have to do is comment out the line of code that adds force based on the direction of the mouse click.
If you’re feeling ambitious, you could also try to allow the user to choose which control scheme they prefer in a settings menu!
7. Would this work on Mobile?
One of the powerful aspects about developing in Unity is that your hard work can pay off on many platforms, including mobile devices. So, let's consider how you might adapt the new mouse control scheme for touch controls, which are common on mobile.
Right now, our code waits for the player to press the left mouse button (Input.GetMouseButton(0)) and then tracks the position of the cursor on the screen (Input.mousePosition). Mobile devices, of course, don't have a mouse, but they do recognize when and where the screen is touched.
By swapping out the mouse inputs with touch inputs, you could theoretically very quickly prepare this game for mobile. Unity's Touch scripting API gives you access to all the touches happening on the screen.
Actually building for mobile is beyond the scope of this course, but if you’re determined to get your game working on mobile, the above guidance will be helpful.
8. Next steps
In this tutorial, you learned to implement a new control scheme using raycasting, an essential tool in game development. This mouse-based control has potential for use on touch-based platforms like mobile, AR, or VR. You used Unity's layer system to refine control responsiveness, ensuring our player character only moves when you want it to.
Next, you’ll continue to optimize your project for your target platform, and you’ll explore Unity's Asset Store to further enhance your game