Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

What is the philosophy behind 3rd person camera/movement controls?

Discussion in 'Scripting' started by Falcoshin, Sep 23, 2017.

  1. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    NOTE: I don't want to go into the Unity Asset store and buy a third person camera or movement script because I learn nothing by doing that.

    What I want to do is create simple third person movement and camera controls similar to what you'd see in an action game like, say, Dark Souls. The problem I've been having is that the attempts I've made previously are flawed practically from a conceptual level. For movement I used something as simple as this:

    Code (csharp):
    1.  
    2. public class PlayerScript : MonoBehaviour
    3. {
    4.     Vector3 directionVector;
    5.  
    6.     const float SPEED = 1.5f;
    7.  
    8.     // Use this for initialization
    9.     void Start()
    10.     {
    11.      
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         if (Input.GetAxisRaw("Horizontal") != 0 || Input.GetAxisRaw("Vertical") != 0)
    18.         {
    19.             directionVector.x = Input.GetAxis("Horizontal") * Time.deltaTime * SPEED;
    20.             directionVector.z = Input.GetAxis("Vertical") * Time.deltaTime * SPEED;
    21.  
    22.             transform.eulerAngles = new Vector3(0, Vector3.Angle(Vector3.forward, directionVector), 0);
    23.         }
    24.         else
    25.         {
    26.             directionVector = Vector3.zero;
    27.         }
    28.     }
    29.  
    30.     // Called after Update
    31.     void LateUpdate()
    32.     {
    33.      
    34.     }
    35. }
    36.  
    Which works as far as movement goes, but is ultimately useless if the camera doesn't follow. I THOUGHT it'd be as simple as just making the camera a child of the character model and while it certainly SEEMS like it works, the problem is that the controls feel unnatural. If you turn and move sideways, for instance, it feels like you should be pressing W or the up key to move forward, but you don't because the input controls are ultimately tied to world coordinates and are not relative to the direction the character is already facing. And worse yet is that, even if I WERE to find a way to make the input controls move the character relative to the direction they are currently facing, I feel it wouldn't be right or "professional". So, down to the very philosophy behind simple third person movement/camera controls in action games, how does this work?
     
  2. mysticfall

    mysticfall

    Joined:
    Aug 9, 2016
    Posts:
    649
    Transform has localPosition property in addition to position to control a game object using its local coordinates. It also provides various methods like TransformDirection / InverseTransformDirection to let you easily convert between world and local coordinate system.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,555
    You don't usually tie inputs to world coordinates usually (unless you know you have a camera oriented a specific way all the time). In 3d, your camera can point any which direction, so your inputs can be any which direction.

    This is called "tank controls". Where pressing up always walks you in the direction.

    It's perfectly "professional"... it's just a very specific style of input. You don't usually see it these days though in contemporary games unless you're evoking some sort of old school feel. For example I'm currently working on a survival horror game, and in the options I allow swapping between "3D" and "Classic Tank" controls (note, survival horrors like RE, Silent Hill, and Alone In The Dark are some of the early games where tank controls became well known... hence the throwback).

    ...

    Though, to me it sounds like you don't want tank controls. You want controls relative to the camera.

    This is how most contemporary 3rd person games play. Your input is relative to what the camera view is. If you push up, you walk forward relative to the camera. So if say the camera was standing upright on the ground, you'd walk into the screen if you pressed up, right sends you right, left sends you left, and down walks towards the screen/camera.

    Since this is relative to the camera... we're probably going to need to know the orientation of the camera. Kind of makes sense.

    Now... there's a shorthand way of doing it, but it limits your camera positioning. Or there is a long hand form, which allows any placement of your camera.

    The limitation of the shorthand is that if you ever positioned your camera birds-eye view above the player... you'd end up with the arithmetic result of a 'zero-vector', which would result in no forward/backward motion. But if your camera is going to be always standing upright like a normal camera and never going birdseye, the algorithm is basically this:

    Code (csharp):
    1.  
    2. Vector2 input = /* input where x is the horizontal of the analogue stick, and y is the vertical of the stick*/;
    3. Camera cam = /* the camera duh */;
    4.  
    5. //first we get the forward of the camera
    6. Vector3 forw = cam.transform.forward;
    7. //now we make said forw parallel to the ground, basically remove the y component
    8. forw.y = 0f;
    9. forw.Normalize();
    10.  
    11. //now we get 'right' relative to that forward, I just do a cross product with 'up' to get it. You could also get the right of the cam.transform and again zero out the y and normalize
    12. Vector3 right = Vector3.Cross(Vector3.up, forw);
    13.  
    14. //now your motion is just going to be x * right + y * forw, include any speed you may want:
    15. Vector3 mv = (forw * input.y * runSpeed) + (right * input.x * strafeSpeed);
    16.  
    17. //apply any other motion you need... like gravity:
    18. mv += Vector3.down * GRAV;
    19.  
    20. //use that mv vector in whatever manner you want... say you have a CharacterController
    21. controller.Move(mv * Time.deltaTime);
    22.  
    And yeah, that's the general idea of it.

    ...

    As for the camera. I seldom child the camera in the player, since it inherits the rotation as well. If you rotate the player when they turn, then the camera is going to spin about.

    I usually use a script that in the LateUpdate it lerps its position towards the player. Including any offset to give it a nice relative position. You can include 'input' checks to rotate the camera here as well... rotating said offset Vector with a quaternion.
     
    mysticfall likes this.
  4. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    I think there's a bit of a misunderstanding. If I understand what you mean by tank controls correctly then that is definitely not what I'm using or even trying to use because the horizontal access isn't used just to change the character's rotation. You're actually intended to move the character with the horizontal keys. The problem is that, because the camera was childed to the character, it SEEMED like you should be pressing forward to move because the camera and the character were facing the same direction. However, you still had to press sideways to move sideways in world space because that's how the input for movement was coded.
     
  5. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Most third person cameras do NOT child the camera to the player. Instead, you make it a separate object that calculates its position and rotation in the Update function or somewhere similar. This is because, as you're finding, the camera's rotation often has nothing to do with the player's rotation, so you don't want to bother inheriting it. You generally want the camera to follow the player's position but not the player's rotation. You also don't usually want it to be moving in perfect sync with the player's position; most use smoothing to drag a bit, and most of them also put a collider on the camera so that it won't go through walls. For Dark Soul's camera, the mouse makes the camera rotate around the player but does not affect the player at all, while the movement keys move the player in the direction the camera is facing but don't directly cause the camera to do anything. The camera is indirectly pulled along when the player moves.

    So, yeah, don't child the camera to the player; make them separate objects. Calculate the camera's position by grabbing the player's position and rotating it around the player with the mouse. Calculate the player's forward vector when he moves by grabbing it from the camera.
     
  6. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    I mean, I did this too, but the problem here is that you can't turn back and see what's behind you. How would I be able to effectively do this? I mean, I COULD make it so the camera rotates back behind the character if he moves in the positive Z direction, but then I run back into the problem I had with sideways movement because now I have to press back to move forward and it's still counter intuitive.

    Yeah, I noticed this as well, but the disorienting controls seemed like a bigger issue to deal with first.

    Ah. See, I can't do that because the mouse has other functions such as clicking on targets for targetting and picking things up.
     
  7. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    I had an epiphany just now that you reposition the camera behind the character if it collides with the camera. Is that what I'm suppose to do? And, if so, how would I configure the game controls so that I don't have to keep pressing back to move back when the camera is safely repositioned?
     
  8. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    You need to find a game with the same camera you are trying to program.

    If there isn't one, then that tells you everything.
     
  9. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    I was originally going with Spyro the Dragon, but I have absolutely no idea how that camera works. But thank you anyway, captain obvious.
     
  10. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    One thing you can do is add a rotate to the camera with a keyboard, and provide a zoom with the mouse. That way the player can decide point of view, etc. Another thing you might consider is using navmesh and having the player move to where you click the mouse, if you hold down the mouse, he keeps walking in that direction. It works pretty well if you are going to be picking objects with the mouse. Otherwise, the games I've played the camera is kind of high and the player turns relative to his own position, not world position. I've seen that type where if he walks close enough into the camera, the camera rotates behind. That's kind of cool. The directions are relative to the camera, but then it suddenly switches to another point of view so the player can move around. I really like third person games because of all the variety with the interfaces and I like watching the character rather than being the character. There are certain games first person works better for, but mostly I prefer 3rd person anymore. I need a controller if it doesn't follow the mouse, though.
     
    Last edited: Sep 24, 2017
  11. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Stardog has a point; you originally said you wanted Dark Souls camera, but now you seem to want something different. I haven't played Spyro so I couldn't tell you how it works. Maybe you want a Zelda cam? Where the player doesn't control the camera directly but instead it sort of follows the player character around lazily as he runs around? For a Zelda cam, the camera can ignore the input entirely. If the player is not moving, he grabs the camera's forward vector when he starts moving and moves relative to that. He keeps that forward vector unless he steers left or right a bit, in which case it's recalculated from the camera's current forward vector. Meanwhile, the camera uses smoothing to follow a position behind the character while also slowly lerping to rotate towards the player's current vector of movement. It's hard to explain in a paragraph, and if that's the camera you want then I'd really recommend buying one or finding a free one on the asset store and looking at how they wrote the actual code.
     
  12. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    I figured out how to do it in the end. I had to add the camera's angle to the angle of the input vector. That was ultimately the crux of it.