Making movement relative to camera

I’m not quite sure how to explain this but here I go.

At the moment the movement for my character is relative to the input received by the analog stick, so an horizontal value and a vertical value.

I followed a small guide to get a better camera in place, and, while I was able to get the camera working, I have absolutely no idea how to make my movement relative to it.

I have a vector3 that always points at the opposite direction of the camera (moveDirection) and a vector3 that points to the front of the character.

I supposed the solution would be to create some kind of angle between the two, but I’m not sure how to proceed from here.

Any suggestions on what I should do?

Here’s my code

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

public class Controls : MonoBehaviour {
    public float speed;
    private Rigidbody rb;
    Vector3 movement;
    Vector3 movementRotation;

    public Vector3 jump;
    public float jumpForce;
    public float gravity;
    public float jumpModifier;

    public ThirdPersonCamera gamecam;
    private float directionSpeed = 3.0f;

    private float moveHorizontal;
    private float moveVertical;
    private float speedPlus = 0.0f;
    private float direction = 0f;
    private Vector3 moveDirection;

    public bool isGrounded = true;

    private Vector3 curLoc;
    private Vector3 prevLoc;

    void Awake(){
        rb = GetComponent<Rigidbody> ();
        jump = new Vector3(0.0f, 2.0f, 0.0f);
        Physics.gravity = new Vector3(0, -gravity, 0);
    }
       
    void OnCollisionStay() {
        isGrounded = true;
    }

    void FixedUpdate () {
        ControllPlayer();
        StickToWorldspace (this.transform, gamecam.transform, ref direction, ref speedPlus);
    }

    void ControllPlayer()
    {
        moveHorizontal = Input.GetAxis ("Horizontal");
        moveVertical = Input.GetAxis ("Vertical");
        Debug.Log (direction);
        movementRotation = new Vector3 (moveHorizontal, 0.0f, moveVertical);

        if (isGrounded == true) {
            // Current movement
            rb.velocity = new Vector3 (moveHorizontal, 0f, moveVertical).normalized * speed;
        } else {
            rb.AddForce (movementRotation * speed * jumpModifier);
        }

        if (Input.GetKey (KeyCode.Space) || Input.GetKey (KeyCode.Joystick1Button1) && isGrounded){
            rb.velocity = new Vector3 (rb.velocity.x, 12.0f, rb.velocity.z);
            isGrounded = false;
        }


        if (movementRotation.sqrMagnitude > 0.1f && isGrounded){
            transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (movementRotation), 1F);
        }

    }

    public void StickToWorldspace(Transform root, Transform camera, ref float directionOut, ref float speedOut){

        Vector3 rootDirection = root.forward;

        Vector3 stickDirection = new Vector3 (moveHorizontal, 0, moveVertical);

        speedOut = stickDirection.sqrMagnitude;

        Vector3 CameraDirection = camera.forward;
        CameraDirection.y = 0.0f;
        Quaternion referentialShift = Quaternion.FromToRotation (rootDirection, Vector3.Normalize(CameraDirection));

        moveDirection = referentialShift * stickDirection;
        Vector3 axisSign = Vector3.Cross (moveDirection, rootDirection);

        // Will always face opposite to the camera
        Debug.DrawRay (new Vector3 (root.position.x, root.position.y + 5f, root.position.z), moveDirection, Color.green);
        //Direction the player is facing
        Debug.DrawRay (new Vector3 (root.position.x, root.position.y + 5f, root.position.z), rootDirection, Color.magenta);

        // Creates Angle between the two
        float angleRootToMove = Vector3.Angle (rootDirection, moveDirection);

//        angleRootToMove /= 180f;

        directionOut = angleRootToMove;
        Debug.Log (directionOut);
    }
}

This is a common question. The key line is here:

        movementRotation = new Vector3 (moveHorizontal, 0.0f, moveVertical);

If you alter the value of movementRotation at that point, you can make it match the camera.
The simplest thing to do is to apply the camera’s rotation to it after the above line:

movementRotation = Camera.main.transform.rotation * movementRotation;

This should get you close to the right movement. If your camera faces downward at all (as most cameras do) and you don’t want that downward angle to “push” your character into the floor, you’ll want to do something a little more complex, which is to make a “flattened” camera rotation before applying it to your vector:

Vector3 camForward = Camera.main.transform.forward;
camForward.y = 0f;
Quaternion camRotationFlattened = Quaternion.LookRotation(camForward);
movementRotation = comRotationFlattened * movementRotation;
5 Likes

That fixed it, thank you!