Moving an object in Unity is straightforward when you stay in either world space or local space. In world space, “forward” always points in a fixed global direction. In local space, “forward” depends entirely on the object’s own rotation.
But things become more interesting when movement needs to be tied to something else entirely—like the camera.
Camera-relative movement means input directions are interpreted based on the camera’s orientation. Pressing “up” moves the character away from the camera’s view, while “down” moves them toward it. This is a common control scheme in third-person games because it keeps movement intuitive regardless of camera rotation.
A simple way to achieve this is to use the camera’s directional vectors instead of the player’s.
For example:
Transform cam;
public float speed = 2;
private void Start()
{
cam = Camera.main.transform;
}
void Update()
{
Vector3 forwardMovement = cam.forward * Input.GetAxis("Vertical");
Vector3 horizontalMovement = cam.right * Input.GetAxis("Horizontal");
Vector3 movement = Vector3.ClampMagnitude(forwardMovement + horizontalMovement, 1);
transform.Translate(movement * speed * Time.deltaTime, Space.World);
}
Because the movement is being calculated from the camera’s orientation, the object now follows the player’s view direction. However, this introduces an important issue.
If the camera is tilted up or down, its forward vector is no longer parallel to the ground. That means pressing forward can unintentionally push the character into the ground or lift it upward, depending on the camera angle. This breaks the expectation of flat, grounded movement.
To fix this, you need to remove vertical influence from the camera’s direction and project movement onto a horizontal plane.
A useful way to do this is by constructing a flat camera position that ignores height differences when calculating direction.
First, you can derive a direction vector like this:
Vector3 direction = (transform.position - Camera.main.transform.position).normalized;
But this alone still includes vertical offset, which can skew movement when the camera is above or below the player.
To correct it, you flatten the camera’s Y position so only horizontal rotation matters:
Transform camTransform = Camera.main.transform;
Vector3 camPosition = new Vector3(
camTransform.position.x,
transform.position.y,
camTransform.position.z
);
Vector3 direction = (transform.position - camPosition).normalized;
Now the direction is based only on horizontal alignment, ignoring elevation differences entirely. This gives you a clean reference for ground-based movement relative to the camera.
With that fixed direction, you can combine inputs so that forward movement follows the camera’s facing direction on the XZ plane, while horizontal movement still uses the camera’s right vector.
Putting it all together:
Transform cam;
public float speed = 2;
private void Start()
{
cam = Camera.main.transform;
}
void Update()
{
Vector3 camPosition = new Vector3(cam.position.x, transform.position.y, cam.position.z);
Vector3 direction = (transform.position - camPosition).normalized;
Vector3 forwardMovement = direction * Input.GetAxis("Vertical");
Vector3 horizontalMovement = cam.right * Input.GetAxis("Horizontal");
Vector3 movement = Vector3.ClampMagnitude(forwardMovement + horizontalMovement, 1);
transform.Translate(movement * speed * Time.deltaTime, Space.World);
}
This approach ensures movement always feels grounded and consistent, regardless of how the camera is tilted or rotated. The character moves relative to the camera’s orientation, but only on a flat plane, which is exactly what most third-person control schemes require.
