Search Unity

Moving character relative to Camera

Discussion in 'Editor & General Support' started by kk99, Jan 31, 2016.

  1. kk99

    kk99

    Joined:
    Nov 5, 2013
    Posts:
    81
    Hi Guys,

    I need little help since I am not making any progress here.
    I am using the Unity Third Person Character Controller presets which is working perfectly for Root Motion Animations.

    In case my animation dont have root Motion I need to add the movement with my script.
    I made this working already for going Forward and Backward relative to the Camera. The camera can be moved freely up and down and rotate around the character.

    What I need is now how to add going RIGHT and LEFT relative to the camera.
    I am not getting it done. Doing Vector3.right or Vector3.left is not working hmmm

    // Fixed update is called in sync with physics
    private void FixedUpdate()
    {
    // read inputs
    float h = CrossPlatformInputManager.GetAxis("Horizontal");
    float v = CrossPlatformInputManager.GetAxis("Vertical");

    if (v > 0)
    {
    transform.Translate(Vector3.forward * v * 1 * speedMeUp * Time.deltaTime);
    }

    if (v < 0)
    {
    transform.Translate(Vector3.back * v * 1 * speedMeUp * Time.deltaTime);
    }

    }


    Oh boy I dont think this is so difficult, but I guess I simply doing it wrong.
    thanks for any help :)
     
  2. AndreiKubyshkin

    AndreiKubyshkin

    Joined:
    Nov 14, 2013
    Posts:
    213
    Ok, this is simple. But not as simple as you're doing it:)

    Vector3.forward is just a constant vector (0f,0f,1f), it is not relative to camera in any way.

    To make your movement relative to the camera you actually need to get the camera transform.

    Code (csharp):
    1.  
    2. void FixedUpdate()
    3. {
    4.         //reading the input:
    5.         float horizontalAxis = CrossPlatformInputManager.GetAxis("Horizontal");
    6.         float verticalAxis = CrossPlatformInputManager.GetAxis("Vertical");
    7.          
    8.         //assuming we only using the single camera:
    9.         var camera = Camera.main;
    10.  
    11.         //camera forward and right vectors:
    12.         var forward = camera.transform.forward;
    13.         var right = camera.transform.right;
    14.  
    15.         //project forward and right vectors on the horizontal plane (y = 0)
    16.         forward.y = 0f;
    17.         right.y = 0f;
    18.         forward.Normalize();
    19.         right.Normalize();
    20.  
    21.         //this is the direction in the world space we want to move:
    22.         var desiredMoveDirection = forward * verticalAxis + right * horizontalAxis;
    23.  
    24.         //now we can apply the movement:
    25.         transform.Translate(desiredMoveDirection * speedMeUp * Time.deltaTime);
    26. }
    27.  
     
    Last edited: Jan 31, 2016
    Darkziss, ABCodeworld, id0 and 20 others like this.
  3. someguywithamouse

    someguywithamouse

    Joined:
    Mar 25, 2018
    Posts:
    9
    I tried, and your code is a bit flawed. It does solve the issue though, but because of the way it was put together it doesnt move towards where (exactly) the camera faces, but rather just relative to the world with the up/down/left/right direction changing depending on an estimate of where the camera is facing. This doesn't make for very accurate control and also to make matters worse it will very easily jump from one direction to another even if you just get a centimeter close to facing left of where you *actually* are facing...

    EDIT: Solved, it wasn't the code causing the issue. It was mostly my setup. Fixed as shown later.
     
    Last edited: Jul 9, 2018
  4. AndreiKubyshkin

    AndreiKubyshkin

    Joined:
    Nov 14, 2013
    Posts:
    213
    I'm sorry you have issues with this tiny piece of code. I only showed the concept and didn't claim you can just simply copy paste and it will work in all cases.

    It works, however. It's just too simple not to work. If you have some "inaccurate" controls, the problem is somewhere else. My guess it's in your InputManager. Check gravity and sensitivity values of Horizontal and Vertical axis.

    Also I'd move the translation from FixedUpdate to usual Update. There's nothing happening there about physics, so there's no need for FixedUpdate.

    P.S. The video isn't helpful
     
  5. AndreiKubyshkin

    AndreiKubyshkin

    Joined:
    Nov 14, 2013
    Posts:
    213
    Oh.. lol. It has nothing to do with InputManager. Obviously the problem is your camera is the child of the player.

    The player tries to move relatevely to camera, but the camera rotates with him. Rethink your player/camera setup.
     
  6. someguywithamouse

    someguywithamouse

    Joined:
    Mar 25, 2018
    Posts:
    9
    [Edited June 28th]
    And also I tried your code again and it seems to behave fine now, except I am still having the same issues with my modified code where the movement direction is incorrect. I am currently fixing that but it's nice to see your code working a bit more like it was expected. The directions aren't solely 4-way or inaccurate in the same way they were before, so clearly what you're doing is working. I just need to figure out how to reverse the incorrect movement directions in my case (which after I've tweaked some settings should be pretty easy).

    Thanks for pointing that out though, I'm starting to get somewhere.
     
    Last edited: Jun 28, 2018
    AndreiKubyshkin likes this.
  7. someguywithamouse

    someguywithamouse

    Joined:
    Mar 25, 2018
    Posts:
    9
    Hello! I've spent a little bit of time improving upon AndreiKubyshkin's code and managed to create a script of my own, and it is working perfectly.

    Also thanks to him for pointing out that I made a mistake with the camera.



    My new code:
    Code (CSharp):
    1. void FixedUpdate(){
    2.             //assuming we're only using the single camera:
    3.                 var camera = Camera.main;
    4.            
    5.                 //Data recieved from CrossPlatformInput Handler:
    6.                   float horizontalAxis = CrossPlatformInputManager.GetAxis("Horizontal");
    7.                   float verticalAxis = CrossPlatformInputManager.GetAxis("Vertical");
    8.                
    9.             float facing = camera.transform.rotation.y;
    10.             float DistanceFromNeutral = 0;
    11.             float transformZ = 0;
    12.             float transformX = 0;
    13.             float finalZ = 0;
    14.             float finalX = 0;
    15.            
    16.             if (facing > -90 && facing <= 90){ //facing forward
    17.                 if(facing >= 0){
    18.                     DistanceFromNeutral = (90 - facing);
    19.                 }else{
    20.                     if(facing < 0){
    21.                         DistanceFromNeutral = (90 + facing);
    22.                     };
    23.                 };
    24.                
    25.                
    26.                 transformX = (1 / 90) * (DistanceFromNeutral);
    27.                 transformZ = 90 - transformX;
    28.             };
    29.            
    30.             //for monitoring and debugging:
    31.             Debug.Log("Main Camera's <color=red>Y rotation</color> is <color=red>" + facing + "</color>, and the <color=blue>Distance from Neutral rotation</color> <color=purple>(0/90/180/270)</color> is <color=blue>" + DistanceFromNeutral + "</color>.");
    32.            
    33.             // continue
    34.            
    35.             finalX = (transformX * verticalAxis) + (transformZ * horizontalAxis);
    36.            
    37.             //if(finalX > 1){
    38.             //    finalX = 1;
    39.             //    };
    40.             // ^^^^ dont use, causes vector3 slowdowns or something ^^^^
    41.            
    42.             finalZ = (transformZ * verticalAxis) + (transformX * horizontalAxis);
    43.            
    44.             //if(finalZ > 1){
    45.             //    finalZ = 1;
    46.             //    };
    47.             // ^^^^ dont use, causes vector3 slowdowns or something ^^^^
    48.            
    49.             transform.Translate((new Vector3( finalX * 0.01f , 0f , finalZ * 0.01f ))* moveSpeed * Time.deltaTime);
    50. }
     
    NPCsZ and wm-VR like this.
  8. Okaymymy

    Okaymymy

    Joined:
    Dec 18, 2018
    Posts:
    1
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class PlayerMovement : MonoBehaviour
    {
    public float playerSpeed;
    public Transform cam;
    Quaternion rotation;
    Vector3 movementSpeed, rot;
    float fwd, side, camY;
    void Start()
    {

    }

    void FixedUpdate()
    {
    CalculatePlayerSpeed();
    Move();
    camY = cam.eulerAngles.y;
    rot = new Vector3(0, camY, 0);
    rotation = Quaternion.Euler(rot);
    transform.rotation = Quaternion.RotateTowards(transform.rotation, rotation, 180);
    }

    void LateUpdate()
    {
    movementSpeed = new Vector3(side*playerSpeed, 0, fwd*playerSpeed);
    }

    void CalculatePlayerSpeed()
    {
    side = Input.GetAxis("HorizontalK")+Input.GetAxis("HorizontalJ");
    fwd = Input.GetAxis("VerticalK")+Input.GetAxis("VerticalJ");
    }

    void Move()
    {

    transform.position += transform.TransformDirection(movementSpeed);
    }
    }


    //this is how i solved it. just used transform.TransformDirection to make the forward direction of my player local instead of world
     
    NPCsZ likes this.
  9. Thank you for sharing, could you please put your code in code tags? After hitting the edit link at the bottom of your post you can find the appropriate button in the toolbar. Thanks!
     
  10. Gryffind96

    Gryffind96

    Joined:
    Mar 21, 2015
    Posts:
    3
    I put my own solution.
    This work with capsule collider, rigidbody and animator controller:
    Code (CSharp):
    1.  
    2.     private float speed = 100f;
    3.     private float walkSpeed = 0.5f;
    4.     private float runSpeed = 1f;
    5.    
    6.    
    7.     private float gravity = 8;
    8.  
    9.     private Rigidbody body;
    10.     private Animator anim;
    11.  
    12.     private Vector3 direction;
    13.     float percent;
    14.  
    15.     private void Awake()
    16.     {
    17.         body = GetComponent<Rigidbody>();
    18.         anim = GetComponent<Animator>();
    19.     }
    20.  
    21.     private void FixedUpdate()
    22.     {
    23.  
    24.  
    25.  
    26.         Move();
    27.  
    28.         if (direction != Vector3.zero)
    29.         {
    30.            HandleRotation();
    31.         }
    32.  
    33.         HandleAnimations();
    34.     }
    35.  
    36.     public void Move()
    37.     {
    38.         float h = Input.GetAxisRaw("Horizontal");
    39.         float v = Input.GetAxisRaw("Vertical");
    40.  
    41.         direction = new Vector3(h, 0, v);
    42.  
    43.         direction = direction.normalized;
    44.      
    45.         if (Input.GetButton("Fire1"))
    46.         {
    47.             percent = runSpeed * direction.magnitude;
    48.             speed = 200f;
    49.         }
    50.         else
    51.         {
    52.             percent = walkSpeed * direction.magnitude;
    53.             speed = 100f;
    54.         }
    55.  
    56.         //CONVERT direction from local to world relative to camera
    57.         body.velocity = Camera.main.transform.TransformDirection(direction) * speed * Time.deltaTime;
    58.     }
    59.  
    60.     public void HandleRotation()
    61.     {
    62.         float targetRotation = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.y;
    63.         Quaternion lookAt = Quaternion.Slerp(transform.rotation,
    64.                                       Quaternion.Euler(0,targetRotation,0),
    65.                                       0.5f);
    66.         body.rotation = lookAt;
    67.  
    68.     }
    69.  
    70.  
    71.     public void HandleAnimations()
    72.     {
    73.         anim.SetFloat("speed", percent, 0.1f,Time.deltaTime);
    74.     }
    75.  
     
    BlackDragonBE likes this.
  11. alex98_

    alex98_

    Joined:
    Jan 30, 2019
    Posts:
    1
    While the rotation looks great...the movement gets the Camera Y so if you look up it turns your character into a space ship.Also it seems to ignore other AddForce usage (adding extra gravity downwards for example)

     
  12. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Yeah this script is so close to being perfect, but the flying player issue is a problem. I can't seem to find a way to stop it from happening haha. Any luck?
     
    h0neyfr0g likes this.
  13. wm-VR

    wm-VR

    Joined:
    Aug 17, 2014
    Posts:
    123
    This is my solution if anybody wants Resident Evil style movements relative to the camera.

    Code (CSharp):
    1.   var cam = Camera.main.transform.TransformVector(transform.forward).normalized;
    2.         var newforward = new Vector3(cam.x,0 , cam.z);
    3.  
    4.         velocity.y += gravity * Time.deltaTime;
    5.  
    6.         var forward = Input.GetAxis("Vertical");
    7.         var sideward = Input.GetAxis("Horizontal");
    8.  
    9.         var direction = newforward * forward + Camera.main.transform.TransformVector(transform.right).normalized * sideward;
    10.  
    11.         controller.Move(direction * speed * Time.deltaTime);
    12.         controller.Move(velocity * Time.deltaTime);
    13.  
    14.         if (chontroller.isGrounded && velocity.y < 0f)
    15.         {
    16.             velocity.y = -2f;
    17.         }
    18.     }
     
  14. gomnoskurvas

    gomnoskurvas

    Joined:
    Aug 23, 2020
    Posts:
    1
    i am having the same problem did you fix it?
    ty in advanced if you did :D
     
  15. Okido

    Okido

    Joined:
    Jan 27, 2014
    Posts:
    5
    Since this is the first result when searching for this problem and was never quite solved, this is my method to make the player move in & face the direction of input, where up is away from the camera's current position. This works with a rigidbody and character controller.

    This also fixes the "space ship" turning (just use the camDirection variable instead of targetDirection on line 13 if you want to keep that)

    Works pretty much out of the box; you just need to use your rigidbody variable in place of _rb, and declare _moveSpeed and _turnSpeed float variables.

    Code (CSharp):
    1. public void MoveInDirectionOfInput() {
    2.    Vector3 dir = Vector3.zero;
    3.  
    4.    dir.x = Input.GetAxis("Horizontal");
    5.    dir.z = Input.GetAxis("Vertical");
    6.  
    7.    Vector3 camDirection = Camera.main.transform.rotation * dir; //This takes all 3 axes (good for something flying in 3d space)    
    8.    Vector3 targetDirection = new Vector3(camDirection.x, 0, camDirection.z); //This line removes the "space ship" 3D flying effect. We take the cam direction but remove the y axis value
    9.      
    10.    if (dir != Vector3.zero) { //turn the character to face the direction of travel when there is input
    11.       transform.rotation = Quaternion.Slerp(
    12.       transform.rotation,
    13.       Quaternion.LookRotation(targetDirection),
    14.       Time.deltaTime * _turnSpeed
    15.       );
    16.    }
    17.  
    18.    _rb.velocity = targetDirection.normalized * _walkSpeed;     //normalized prevents char moving faster than it should with diagonal input
    19.  
    20. }
     
    Last edited: Oct 6, 2020
  16. PPLorux

    PPLorux

    Joined:
    Jul 29, 2017
    Posts:
    8
    Thanks, it works pretty good indeed but I tried it on my project (with some slight changes to fit the new input system) and I got a weird rotation shaking effect sometimes. After some tests it appears that this happens even when the rotation part of the code isn't reached (if dir != Vector3.zero).

    Any ideas?

    EDIT : Solved! I was using a character controller and a non kinematic rigidbody. Toggled kinematic and now the issue is gone!
     

    Attached Files:

    Last edited: Oct 3, 2020
    Okido likes this.
  17. Okido

    Okido

    Joined:
    Jan 27, 2014
    Posts:
    5
    ah nice, glad to hear you solved it! I hadn't tried with a character controller so that's good to know