0

So I have a simple script to move a character. The problem is that no matter where i'm looking at (my y rotation) it always makes me go the direction if I try to go forward, but I want it to go toward where i'm looking when I go forward or relative to where i'm looking for any direction. HOw can I do this ? (also I do not want to use a already existing fps controller) transform.forward works but only if I go forward or backward, not for left right or diagonal. (placed on player)

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

public class player : MonoBehaviour
{
public float speed;
Rigidbody rb;

void Start()
{
    rb = gameObject.GetComponent<Rigidbody>();
}


void Update()
{
    float x = Input.GetAxis("Horizontal");
    float z = Input.GetAxis("Vertical");
    rb.velocity = new Vector3(x*speed.rb.velocity.y,z*speed);
}
}

for my camera, I am using a script I found online: (placed on player)

using System;
using UnityEngine;

public class mouseLook : MonoBehaviour
{
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 15F;
public float sensitivityY = 15F;
public float minimumX = -360F;
public float maximumX = 360F;
public float minimumY = -60F;
public float maximumY = 60F;
Rigidbody rigidbody;
float rotationY = 0F;

void Update ()
{
    if (axes == RotationAxes.MouseXAndY)
    {
        float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse 
X") * sensitivityX;             
        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
        rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
        transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
    }
    else if (axes == RotationAxes.MouseX)
    {
        transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0);
    }   
    else
    {
        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
        rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
        transform.localEulerAngles = new Vector3(-rotationY, 
transform.localEulerAngles.y, 0);
    }
}

void Start ()
{
    Cursor.lockState = CursorLockMode.Locked;
    rigidbody = gameObject.GetComponent<Rigidbody>();
    if(GetComponent<Rigidbody>())
    {
        GetComponent<Rigidbody>().freezeRotation = true;
    }
}
}
Samuel Fyckes
  • 322
  • 1
  • 5
  • 17

3 Answers3

1

You can use the object's transform to turn an arbitrary direction in local space to a direction in world space:

float x = Input.GetAxis("Horizontal"); 
float z = Input.GetAxis("Vertical");

// Some sticks/arrow keys will let both axes be 1 at once.
// ClampMagnitude ensures diagonals obey our max speed.
Vector3 localVelocity = Vector3.ClampMagnitude(new Vector3(x, 0, z), 1) * speed;

rb.velocity = transform.TransformDirection(localVelocity);

Note that, as written, this can cause the character to try to fly upward if looking to the sky. You can avoid that by instead forming a quaternion representing your "foot space" ground orientation (say, by getting the normal of the ground under you from a raycast), and rotating your local velocity by that quarternion. I show an example of something like that here.

DMGregory
  • 134,153
  • 22
  • 242
  • 357
  • Not sure to understand your answer.... isn't the a way to only detect my Y rotation so it doesn't matter if i'm looking up or down ? – Samuel Fyckes Mar 22 '20 at 13:09
  • Yes there is. The way I showed you is one such way. If there's a particular part of the method that confused you, please describe where you got lost and we can clarify it further. – DMGregory Mar 22 '20 at 13:11
0

One suggestion is to use TransformDirection:

Vector3 v = new Vector3(x, 0, z);
rb.velocity = transform.TransformDirection(v);

Another is to use AddRelativeForce:

rb.AddRelativeForce(v, ForceMode.Acceleration);

I would prefer the second option, but keep in mind that method is adding to the velocity instead of overriding it each update.

Also, you should only use the RigidBody methods inside FixedUpdate().

Sirius 5
  • 139
  • 6
  • The first one still makes me go in the same direction (don't fix the problem). When I try the second one, I just can't move. – Samuel Fyckes Mar 22 '20 at 13:06
  • Are you using the Player's transform or the Camera's? It sounds like you need to use the Camera's transform, i.e. Camera.main.transform.TransformDirection(v); – Sirius 5 Mar 22 '20 at 13:08
  • Remember to cache the result from Camera.main so that you are not calling it every frame, in Start() for example. – Sirius 5 Mar 22 '20 at 13:09
  • Also, DMGregory's answer is better than mine, and he beat me by 2 minutes, lol – Sirius 5 Mar 22 '20 at 13:10
  • @Samuel It sounds like you may have forgotten to rotate your player character to match the camera's facing direction. Try looking at your character in the scene view when playing the game — as you turn your camera, does it start to look out the side/back of your character's head, instead of the front? – DMGregory Mar 22 '20 at 13:11
  • Ok thanks, and yea I don't know how he does that but he seem to know everything about everything it's killing me xD – Samuel Fyckes Mar 22 '20 at 13:11
  • well, since I placed the camera script on the player (it still works fine) the player's the one rotation when I look around – Samuel Fyckes Mar 22 '20 at 13:12
0

Just use transform., you get a vector that is pointing relative to the object.

If you don't want object to fly up when its transform is looking into the sky, do this:

    float x = Input.GetAxis("Horizontal");
    float z = Input.GetAxis("Vertical");

    Vector3 forward = transform.forward; 
    //here, make Y component of the vector 0, thus only using it for direction on the flat plane.
    forward.y = 0;

    rb.velocity = forward * speed * z + transform.right * speed * x;
Nick
  • 561
  • 4
  • 21