Trying to get my player to move forward, backward, left and right using WASD in relation to camera direction. My problem cannot be solved using AddRelativeForce, my player is a sphere.

Here’s some context: I’m trying to make a simple 3D platformer game as a rite of passage into Unity and C# development. I can move around my sphere using WASD and AddForce, and there was no issue with that because my camera position was fixed, and so was the relation. I followed a tutorial to get an orbital camera that can be controlled via the mouse, and that worked out nicely.

I soon realized that now that I have an orbital camera, ‘W’ doesn’t mean forward anymore - direction is locked on an axis. This is where things start to get a bit muddy for me, I tried to use some math to get the direction the camera is facing and use AddForce in relation to the camera direction (I probably did that math wrong).

After I tried doing that for about 2 hours, I thought I’d try to scour through google one more time, then I found AddRelativeForce - for a moment, I really thought that was going to be the answer, so I implemented it. Very soon after that, I realized, “Oh, wait a minute… my player rolls around, so local z and x aren’t always flat, oops.” And that’s where I am now:

I don’t understand what math to use, and I can’t find any tutorials, and nobody else seems to have asked, at least not that I can find. Here’s my code with the (most likely incorrect) math technique, the issue I’m having is in the FixedUpdate function, between lines 79 and 94:

using UnityEngine;

public class PlayerController : MonoBehaviour {

    public GameObject playerCam;
	public float forwardForce = 50f;
	public float speed = 5f;
    public float jumpHeight = 6f;

	private Rigidbody rb;
    private bool up;
    private bool down;
    private bool left;
    private bool right;
    private bool jump;
    private bool brake;

	// Use this for initialization
	void Start() {
		rb = GetComponent<Rigidbody>();
	}

    // Update is called once per frame
    void Update()
    {

        if (Input.GetKey("d"))
        {
            right = true;
        }
        else
        {
            right = false;
        }
        if (Input.GetKey("a"))
        {
            left = true;
        }
        else
        {
            left = false;
        }
        if (Input.GetKey("w"))
        {
            up = true;
        }
        else
        {
            up = false;
        }
        if (Input.GetKey("s"))
        {
            down = true;
        }
        else
        {
            down = false;
        }
        if (Input.GetKey("space"))
        {
            jump = true;
        }
        else
        {
            jump = false;
        }
        if (Input.GetKey("x"))
        {
            brake = true;
        }
        else
        {
            brake = false;
        }
    }
	
	void FixedUpdate() {
        var heading = transform.position - playerCam.transform.position;
        var distance = heading.magnitude;
        var direction = heading / distance; // grabbed this example off of the unity reference

        if (left){
            rb.AddForce(new Vector3(-1 * speed * Time.deltaTime, 0, 0).magnitude * direction, ForceMode.VelocityChange);
        }
		if (right){
            rb.AddForce(new Vector3(1 * speed * Time.deltaTime, 0, 0).magnitude * direction, ForceMode.VelocityChange);
        }
		if (up){
			rb.AddForce(new Vector3(0, 0, -1 * speed * Time.deltaTime).magnitude * direction, ForceMode.VelocityChange);
		}
		if (down){
			rb.AddForce(new Vector3(0, 0, 1 * speed * Time.deltaTime).magnitude * -direction, ForceMode.VelocityChange);
		}
        if (jump)
        {
            if (rb.velocity.y < .01 && rb.velocity.y > -.01) // I know that this method allows for a potential jump mid-peak, going to rewrite later 
            {
                rb.AddForce(0, 1 * jumpHeight, 0, ForceMode.Impulse);
            }
        }
        if (brake)
        {
            rb.AddForce(-rb.velocity / 18, ForceMode.Impulse); // This slows down the sphere in all axes, going to replace this later
        }
    }
}

First of all, for a simple platformer, I would encourage you to write your own simple physics system (not as hard as it sounds) instead of using the native physics in Unity. By doing that you will learn a lot more and ultimately have something that suits your situation a lot better than the native option.

Secondly, I answered this very question a while ago, so I’ll forward you to that: Rotate an object based on Camera's axis - Questions & Answers - Unity Discussions