Player movement rotation in relation to camera?

So I’ve got a script where the character turns towards the movement direction. So for example, if I hold “A” the they will turn and move left on the x axis in world space.

What I need now, is for the character’s rotation to be acting in relation with the camera’s forward direction.

Here’s the code I have:

public Transform playerCamera;

public float moveSpeed;
public float rotationSpeed;

float translation;
float strafe;

void FixedUpdate () {

    //Movement
    strafe =  Input.GetAxis ("Horizontal") * moveSpeed * Time.deltaTime;
    translation = Input.GetAxis ("Vertical") * moveSpeed * Time.deltaTime;

    Vector3 movement = new Vector3 (strafe, 0f, translation);

    if (movement != Vector3.zero) {
        transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (movement), rotationSpeed);
    }

    transform.Translate (playerCamera.TransformDirection(movement));
}

And here’s a simpler explanation:

What I have now
The character will always turn to the key input movement in world space, so if I were to rotate the camera 90 degrees to the right, and then press “A”, the player will now move backwards, or towards the camera since that is still “left” in world space.

What I need
The character takes the forward direction of the camera in regard when turning. So if I turn the camera like before (90 degrees to the right), and then press “A”, the character will now move forward in world space, which will be “left” in the camera’s view. Pretty much what happens in MMOs.

And just to clarify, I don’t want the player’s rotation to always be relevant to the camera. So I don’t want the player turning with it, I just want the camera’s forward direction to act as the movement turning basis for the character, rather than the world space.

Any idea how I could change that, or add to it, to make the character’s movement rotation be relevant to the camera’s forward position rather than world space?

I think you kind of answered yourself in your question :slight_smile:

pretty sure, in scenario B your position is: -camera.transform.right

Side note: I slightly disagree with all games being that way. My favourite type of movement is independent. I can turn my camera around anywhere, but my player will always move relative to its own orientation :wink: but not important lol

1 Like

Well the problem is, I know the logic behind it and how to solve it, but I don’t know what code exactly to use (what commands and stuff).

And I think when you wrote your reply, I haven’t actually updated the post with the code. Could you have a look, and let me know what I should alter?

Sure, ya … I think you can can use: transform.Translate(camera.TransformDirection(movement)); // space self.
I think that should read like: local to world from the camera’s transform, then translated locally to the player. :slight_smile:

That’s an educated guess :slight_smile: Let me know if it works. lol We’ll be educated either way.

2 Likes

It’s a bit weird.

The left and right movement keys rotate the character in world space, and make him go towards the camera (move back in relation to the camera), and both up and down move the character away from the camera, and also rotate in world space.

Oh and just fyi, when I said “camera’s forward direction” I meant it in world space, as in if the camera is looking down, but the top of it is facing a certain direction, then the player should move in that direction. Just thought i’d make that clear.

Imagine it like you’re looking down at the ground, but you’re still facing a certain direction. Because you can’t physically walk into the ground, so only on the x and z axis.

In my limited testing here, it seems to be working okay for me.

Just updated my original post, explaining what’s happening more clearly after doing more testing, and also updated the code.

Are you simply asking for your character to not take the camera rotation as reference for it’s movement?

No, I’m asking for the opposite.

Think of any MMO ever (or most of them) for an idea of what I’m talking about. If the camera is looking in a certain direction towards a point on the x/z plane (horizontal plane), the player will walk towards that direction if the forward button is pressed (be it W or the Up arrow), but will not change its y movement or physics in any way, even if the camera is looking straight down. That’s essentially what I want to achieve.

But currently what’s happening, is all the rotations act in world space rather than in reference with that camera direction, and the movement is all weird. And if i look downwards, the character moves really slowly and starts jumping (like I stated before), as if he was trying to walk right into the ground.

Well then your explanation needs some updating. In anycase I now get what you want. Be warned however this is a quick fix and not ideal for a final product. I’m merely adding to the fixed update

 void FixedUpdate () {

    //Movement
    strafe =  Input.GetAxis ("Horizontal") * Time.deltaTime;//removed movespeed from these
    translation = Input.GetAxis ("Vertical") * Time.deltaTime;

    Vector3 movement = new Vector3 (strafe, 0f, translation);

    if (movement != Vector3.zero) {
        transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (movement), rotationSpeed);
    }
    Vector3 targetDir = playerCamera.TransformDirection(movement);//this is merely a direction now
    target.y = 0;
    transform.Translate (targetDir.normalized * moveSpeed);//speed applied here instead
}

What I would do to properly solve the problem, is parent the camera to an empty gameobject which is meant to rotate along the Y axis only, an the now child object camera only rotates online it’s X axis. You then use the camera’s parent rotation for your character’s movement. With the aforementioned camera setup, there is no need for this nifty conversion every frame.

1 Like

That solves the movement, thanks. :slight_smile:

Now I just need it to also change the rotation properly.

Right now the rotation still behaves in world space.

Also, one small thing. The player moves insanely fast. So much so, that I have to set the moveSpeed to 0.1 for it to act just above normal speed. And I have to keep “Space.World” in the translate line, otherwise it still moves weirdly.

Glad you got it working.

I feel like your movement being too fast is because of how you’re using Time.deltaTime, as you should,but normalizing your vector after (essentially undoing that). Do the Time.deltaTime to modify move speed later in your function, rather than modifying your movement vector.

Sorry, on my cell, hopefully these ramblings of mine are coherent.

1 Like

I can’t get the rotation working. I’ve tried a lot of stuff, and I even read up on some of the manual pages.
I understand how the movement is being changed, but for some reason I can’t seem to understand how to transfer that process into the rotation part of the code.

I did find somewhat of a solution.

//Changing this
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (movement), rotationSpeed);

//To this
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (targetDir), rotationSpeed);

But after doing so, if I hold down one of the keys, and move the camera around, it causes the character to jitter while turning. And there is still the problem of the character moving slower if I look down. Any idea how to solve this?

If I am understanding what you want, correctly, your movement is similar to the movement that I have in the current game I’m building, which is actually a twin stick shooter, with right stick controlling look direction, but when using just left stick, it moves exactly like you describe… I believe. Left moves left across the screen, up goes up the screen, no matter how the camera is rotated… correct? If not, then all the crap to follow is not what you want :frowning:

It’s top down game though, and that might change things. You’ll also run into some other “gotchas”, which we can deal with on a case basis (your diagonal movement may be faster… your movement on one axis may be slow…).

Anyways, here’s the basic concept of my controls that I’m using, yours may vary depending on the axis your character turns on (Y is up in my world, and the character rotates on Y… they also don’t move up/down at all…everything on one plane).

moveDirection = Vector3.zero; // This "zeroes" moveDirection vector, as when it loops through each iteration, it might have a value here...
moveDirection += Camera.main.transform.forward * inputMoveVertical;
moveDirection += Camera.main.transform.right * inputMoveHorizontal;
//I also do moveDirection.y = 0;... you may or may not want that...
// blah blah blah, some other manipulation you won't care about, and my movement code...

transform.rotation = Quaternion.LookRotation(moveDirection); // (I actually do a slow rotation, but i've kept it simple for you here)
1 Like

Sorry, pretty sure I took your meaning wrong, now that I read your post again!

I also just tested the movement some more, and I do move faster diagonally.

There’s a few ways of handling that. The short answer is you need to normalize your movement vector. If your input is keyboard only, or you only have a “1 or 0” movement (no in between), the solution is also super short… use .Normalize(). If you have analog (joystick) input, then read on…

Not sure what your code looks like at this point, but the reason diagonal movement is often faster than straight Vertical or Horizontal movement is because each of these have a magnitude of 1 unit (simplifying here) when you apply your movement fully in whatever direction (up,down, left or right). However, when you apply both together, fully, your magnitude is actually 1.41… think Pythagorean Theorem, back in school. A(horizontal) squared plus B(vertical) squared = C (magnitude) squared. So what is C (magnitude)? C = the square root of A squared + B squared, so in our example of fully diagonal, it’s the square root of 2… or 1.41 and a bunch of other numbers :slight_smile:

So, really, full bore diagonal really needs to be about 0.705 horizontal, and 0.705 vertical. But that’s not the case when you’re partially moving your joystick, and that complicates things a bit, but thankfully there’s easy enough ways to do it.

This is the method I use:

if (moveDirection.magnitude > 1)
     moveDirection = moveDirection / moveDirection.magnitude;

So translated into stuff we non-mathy types can understand… if the magnitude of your movement vector (the distance the player is trying to move that particular frame) is greater than 1, then just divide the movement vector by the magnitude. There’s info on why that works how it does here. But most people won’t care… it just does what you need it to. There’s other tricks out there, but I find they result in some other problems.