Search Unity

Move camera relative to rigidbody's rotation

Discussion in 'Scripting' started by Jacebook, Apr 3, 2018.

  1. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Hi, I've been having trouble with this today, and I haven't found a thread specifically like mine. I have looked :)

    My character/rigidbody turns around, and I need the camera to follow her. So when she turns/rotates, the camera needs to rotate and always be behind her. That way you can always see what is in front of her when she's moving or rotating.

    So far I have it so my script has the camera follow her forward/back movements. Hoping someone can help me find a way to have the camera always sit behind her, no matter which was she turns! :)

    Code (CSharp):
    1.  
    2.     public Rigidbody rigidbody;
    3.     public Vector3 offset;  // set to (0,5,-7)
    4.     public Camera camera;
    5.     public VirtualJoystick joystick;
    6.     private Vector3 MoveVector { set; get; }
    7.     public float moveSpeed = 30.0f;
    8.     public float rotateSpeed = 300.0f;
    9.  
    10.     void Update() {
    11.         camera.transform.position = rigidbody.position + offset;
    12.  
    13.         if (Input.GetKey(KeyCode.LeftArrow))
    14.         {
    15.             rigidbody.transform.Rotate(0, (0 - rotateSpeed) * Time.deltaTime, 0, Space.World);
    16.         }
    17.  
    18.         if (Input.GetKey(KeyCode.RightArrow))
    19.         {
    20.             rigidbody.transform.Rotate(0, rotateSpeed * Time.deltaTime, 0, Space.World);
    21.         }  
    22.  
    23.         if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.DownArrow))
    24.         {
    25.             MoveVector = PoolInput();
    26.             Move();
    27.         }
    28.  
    29.     }
    30.  
    31.     private void Move()
    32.     {
    33.         rigidbody.AddForce((MoveVector * moveSpeed));
    34.     }
    35.  
    36.     private Vector3 PoolInput()
    37.     {
    38.         Vector3 dir = Vector3.zero;
    39.  
    40.         dir.x = joystick.Horizontal();
    41.         dir.z = joystick.Vertical();
    42.  
    43.         if (dir.magnitude > 1)
    44.             dir.Normalize();
    45.  
    46.         return dir;
    47.     }
    48.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    You can use the SmoothFollow script that is part of Unity3D Standard Assets. This gives a nicely-controllable context to adjust how snappy the camera feels.

    You can also just parent the camera below your character, and align it so that it is above and behind the character, then it will whip around automatically, but it will always be precisely behind your character, or wherever you initially place it.
     
  3. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Thanks Kurt! I didn't think of putting the camera as the character's child. Now I've got them both rotating together, but now just need to figure out how to have the camera move its position to be behind her when she rotates! :)
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I don't quite understand that comment. If you put the camera as a child of your player, then when your player turns, the camera should turn to always be behind it!

    The only way this might not be true is if the root object of your player is not actually turning, but only a sub-object is turning. I.e., maybe the root GameObject is always pointing the same way, and then the character graphics are an object or two below it, and those are turning?

    In that case putting the camera under the root object won't get you what you want. You would have to put it under the actual game object that is turning around in the world.

    If that entangles something else, then you might need to modify your character controller so that it not only turns your visible character, but also turns a colocated invisible GameObject in the character hierarchy, and then you hang your camera "under" that.
     
  5. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Not to interrupt this discussion, but I think this is the most basic idea of what you're trying:
    Code (csharp):
    1. camTrans.position = transform.position + transform.TransformDirection(offset);
    2. camTrans.rotation = transform.rotation;
     
    Jacebook likes this.
  6. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    OMG .. it works :D Thanks!
     
  7. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Additionally... I've noticed my rigidbody/character (while looking at Transform in the inspector) is rotating in the y-axis. And after rotating her and move forward, she runs backwards or sideways. I'm a little confused here (?)
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    For rigidbodies you should use the RigidBody.MoveRotation() so the physics engine is involved in your turning.

    To isolate what is happening with your weird rotation, start the game, pause it, then plunk a cube or something as a child of the part of your character that you want to turn, and move it slightly ahead of the character. This gives you a good idea of what is rotating where.
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    One thing to think about is that you will have issues with your rotation and movement the way it is.

    Imagine you are trying to move left.. it is now rotating plus moving to your 'local left' (but that local left is always changing). basically you are spinning. :)

    Depending on how you want your game to work, you can choose what ya like.

    Some common things I see are:
    1) allow only moving forward, but you can rotate, so basically you go any direction.. you just have to rotate there first.
    2) strafing : sideways movement, without changing the rotation.
    3) 8 directional movement
     
  10. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Oh, sorry I meant to respond about the rotation not changing.. that could only happen if you're rotating another object. Otherwise, you should see a change.
    As for why the object is going in the wrong direction, that's probably because you're using a world direction force.

    You can use transform direction again, and/or think of it this way:
    desired direction = transform.forward * v + transform.right * h
    * transform.forward / transform.right are locally foward/right.
     
  11. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Ahh... yes this is where the problem is. My rotation is using a world rotation instead of local to the rigidbody/camera. I'm now just trying to figure out the exact coding for the local transform/rotation using your suggestion of .TransformDirection. Sorry for being a pain today, I'm still pretty new to Unity and C#.
     
  12. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Hmm.. I think world and local can work.

    What I was trying to say is that your current code tries to do this when going left/right:
    rotate in the direction plus also travel there. I have omitted the part about going in the wrong direction here, because even if you had the right direction, going left while also rotating to the left would be a "shifting left".

    That brings us back to the 3 options I listed (or maybe some other variation).
     
  13. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Yeh I get what you're saying. I'm just a little confused with it, because there's plenty of FPS games where you walk around, change direction, and still move 'forward' without the character moving off in the wrong direction.
     
  14. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Of course.. Just decide what you want.

    I haven't played an FPS in a long while, but would that be like:
    2 keys for strafing left/right (based on current forward)
    forward / back based on rotation.
    2 other keys for rotating left/right but do not move?
     
  15. Jacebook

    Jacebook

    Joined:
    Jan 11, 2018
    Posts:
    9
    Well actually.... it's for mobile devices, so I'm putting in a 'virtual joystick' to have the control on the screen. My current method of keyboard input keys has been useful for testing and development but I'll change that later. So if it would somehow work (yet to be tested), but have the single joystick use forward/back for moving forwards and backwards, and the left/right for turning. So movement and rotation on the same joystick control.
     
  16. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I would try to have the rotation be from the horizontal and the forward/back from the vertical.
    You can reach any rotation that way. In other words, do not use the horizontal for movement directly.

    As far as I know, that's all that can make sense to me with that setup.
     
  17. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I think I know what your problem is: you need to multiply the input vector by your facing rotation, otherwise pressing RIGHT will always move you +X regardless of which way you're facing.

    Generally, the way this is done is to first gather the desired inputs into a Vector3 (put the "Horizontal" component into X and the "Vertical" component into Z).

    Code (csharp):
    1.  Vector3 myRawInput = new Vector3( Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    Now that it is in that Vector3, before you add it to your player, do this:

    Code (csharp):
    1.  Vector3 myTurnedInput = transform.rotation * myRawInput;
    Now you go and use myTurnedInput to move your character, multiplying it by your desired walk speed and also by Time.deltaTime as usual.

    Assuming this script is on the player itself, this will "turn" the inputs appropriately to their facing.
     
    aber416373 likes this.