Search Unity

[UNSOLVED] Camera / Player Movement Issue

Discussion in 'Scripting' started by DRRosen3, Nov 27, 2014.

  1. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    The problem I'm having is that while the player is in motion the camera is jerking back and forth between the player.transform.position and where it's SUPPOSED to be.

    Here is the Camera script...


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CameraController : MonoBehaviour {
    5.  
    6.     public Transform cameraTarget;
    7.     private float x = 0.0f;
    8.     private float y = 0.0f;
    9.  
    10.     private int mouseXSpeedMod = 5;
    11.     private int mouseYSpeedMod = 3;
    12.  
    13.     public float maxViewDistance = 25;
    14.     public float minViewDistance = 1;
    15.     public int zoomRate = 30;
    16.     private int lerpRate = 2;
    17.     private float distance = 3;
    18.     private float desiredDistance;
    19.     private float correctedDistance;
    20.     private float currentDistance;
    21.  
    22.     public float cameraTargetHeight = 1.5f; //This number is the height of the camera's target. i.e. The player.
    23.  
    24.     void Start () {
    25.         Vector3 angles = transform.eulerAngles;
    26.         x = angles.x;
    27.         y = angles.y;
    28.  
    29.         currentDistance = distance;
    30.         desiredDistance = distance;
    31.         correctedDistance = distance;
    32.     }
    33.  
    34.     void Update(){
    35.         if(cameraTarget == null)
    36.             cameraTarget = GameObject.FindGameObjectWithTag("Player").transform;
    37.  
    38.     }
    39.  
    40.     void LateUpdate () {
    41.         if(Input.GetMouseButton (1)){
    42.             x += Input.GetAxis("Mouse X") * mouseXSpeedMod;
    43.             y -= Input.GetAxis("Mouse Y") * mouseYSpeedMod;
    44.         }
    45.  
    46.         else if(Input.GetAxis("Movement") != 0 || Input.GetAxis("Rotate Player") != 0){
    47.             float targetRotationAngle =  cameraTarget.eulerAngles.y;
    48.             float cameraRotationAngle = transform.eulerAngles.y;
    49.             x = Mathf.LerpAngle(cameraRotationAngle, targetRotationAngle, lerpRate * Time.deltaTime);
    50.         }
    51.  
    52.         y = ClampAngle(y, -50, 80);
    53.  
    54.         Quaternion rotation = Quaternion.Euler(y, x, 0);
    55.  
    56.         desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs (desiredDistance);
    57.         desiredDistance = Mathf.Clamp(desiredDistance, minViewDistance, maxViewDistance);
    58.         correctedDistance = desiredDistance;
    59.  
    60.         Vector3 position = cameraTarget.position - (rotation * Vector3.forward * desiredDistance);
    61.  
    62.         RaycastHit collisionHit;
    63.         Vector3 cameraTargetPosition = new Vector3(cameraTarget.position.x, cameraTarget.position.y + cameraTargetHeight,cameraTarget.position.z);
    64.  
    65.         bool isCorrected = false;
    66.         if(Physics.Linecast(cameraTargetPosition, position, out collisionHit)){
    67.             position = collisionHit.point;
    68.             correctedDistance = Vector3.Distance(cameraTargetPosition, position);
    69.             isCorrected = true;
    70.         }
    71.  
    72.         currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomRate) : correctedDistance;
    73.  
    74.         position = cameraTarget.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -cameraTargetHeight, 0));
    75.  
    76.         transform.rotation = rotation;
    77.         transform.position = position;
    78.     }
    79.  
    80.     private static float ClampAngle(float angle, float min, float max){
    81.         if(angle < -360){
    82.             angle += 360;
    83.         }
    84.         if(angle > 360){
    85.             angle -= 360;
    86.         }
    87.         return Mathf.Clamp(angle, min, max);
    88.     }
    89. }
    90.  

    And here is the PlayerMovement script...


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [RequireComponent (typeof(CharacterController))]
    5. public class Movement : MonoBehaviour {
    6.  
    7.     public float rotateSpeed = 250f;
    8.     public float moveSpeed = 5f;
    9.  
    10.     private CharacterController controller;
    11.     private Transform myTransform;
    12.     private Animator anim;
    13.  
    14.     void Awake(){
    15.         controller = GetComponent<CharacterController>();
    16.         myTransform = transform;
    17.     }
    18.  
    19.     void Start () {
    20.         anim = GetComponent<Animator>();
    21.     }
    22.  
    23.     void Update () {
    24.         Turn();
    25.         Walk();
    26.     }
    27.  
    28.     private void Turn(){
    29.         if(Mathf.Abs(Input.GetAxis("Rotate Player")) > 0){
    30.             myTransform.Rotate(0, Input.GetAxis("Rotate Player") * Time.deltaTime * rotateSpeed, 0);
    31.             anim.SetFloat("Direction", Input.GetAxis("Rotate Player"));
    32.         }else{
    33.             anim.SetFloat("Direction", 0);
    34.         }
    35.     }
    36.  
    37.     private void Walk(){
    38.         if(Mathf.Abs(Input.GetAxis("Movement")) > 0){
    39.             controller.SimpleMove(myTransform.TransformDirection(Vector3.forward) * Input.GetAxis("Movement") * moveSpeed);
    40.             anim.SetFloat("Speed", Input.GetAxis("Movement"));
    41.         }else{
    42.             anim.SetFloat("Speed", 0);
    43.         }
    44.     }
    45.  
    46. }
    47.  

    By the way, I changed the standard Unity input names of Horizontal and Vertical to Rotate Player (used to be Horizontal) and Movement (used to be Vertical). Thanks in advance for any help!
     
  2. StickyKeyStudios

    StickyKeyStudios

    Joined:
    Jun 23, 2014
    Posts:
    33
    Hello, - PLEASE READ THE EDIT

    Is this suppose to be a first person script, or a 3rd person script (Such as what you would find in Uncharted 1/2/3, Grand Theft Auto, Goat Simulator, etc)?

    If this is suppose to be a first person script, if you parent that camera to the head of your character you'd get the effect you'd be desiring, otherwise, try lerp-ing your camera's position. While this may not seem like the best of ideas, it would most likely help a bit.

    I see you are using a CharacterController (as read from by "controller.SimpleMove()") I'd suggest taking the current velocity of your CharacterController
    Code (CSharp):
    1. Vector3 velocity = controller.velocity;
    and then doing some math with your camera. The kind of math we're doing is pretty simple, and is actually what you would need to do if you were implementing multiplayer (So this is also sort of a win-win). You need to create a few variables for this
    Code (CSharp):
    1. private float lastSyncTime = 0.0f;
    2. private float syncDelay = 0.0f;
    3. private float syncTime = 0.0f;
    4. private Vector3 syncEndPosition = Vector3.zero;
    5. private Vector3 syncStartPosition = Vector3.zero;
    Then you're going to want to check every frame (Update method) for the time since the last frame using (syncDelay), you're also going to want to reset the syncTime to 0.0f, and set the lastSyncTime to the current time (Time.time)
    Code (CSharp):
    1. syncTime = 0f;
    2. syncDelay = Time.time - lastSyncTime;
    3. lastSyncTime = Time.time;
    Then, to get the new syncEndPosition and update the syncStartPosition, you simply do
    Code (CSharp):
    1. syncEndPosition = camera.transform.position + syncVelocity * syncDelay;
    2. syncStartPosition = transform.position;
    And then, as simple as it may appear, set the camera's transform (This may need modifying to fit the positioning and what not of how you'd like your camera to be)
    Code (CSharp):
    1. syncTime += Time.deltaTime;
    2. transform.position = Vector3.Lerp(syncStartPosition, syncEndPosition, syncTime / syncDelay);

    EDIT:
    I completely overlooked something. Wow, I feel sort of dumb. You're issue is most likely that when you lerp the camera's position, it starts moving, and then when the next Update() is called, it resets the camera's position and starts a new lerp. You may need to stray away from using a lerp as it isn't very necessary in your case.
     
  3. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Well I skipped down to you "EDIT" portion. The reason there is ANYTHING at all in the Camera script's Update function is because I Instantiate my player at the start of the scene. Since the player isn't instantianted until the start, the Camera wouldn't have anything to find at IT'S start. Unless...there's another way to accomplish this without the Camera checking to see if it's target is null every frame?

    EDIT - Oh...and yes this is a 3rd person camera.
     
    Last edited: Nov 27, 2014
  4. StickyKeyStudios

    StickyKeyStudios

    Joined:
    Jun 23, 2014
    Posts:
    33
    Yeah, ignore my original post except for the edit. If your Player is a prefab, you could make the camera a child of that prefab and then put the code for your camera placement as a component of your camera. Whenever you instantiate the player prefab, the camera will then be instantiated with it (Since the camera is actually a part of that player prefab). You would then need to figure out what is wrong with your Camera glitching it's movement. I still believe it's most likely the lerping, however I could be wrong.
     
  5. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    So with me not using the lerp, where do you think I should make the change in the camera's script?
     
  6. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    So what I've changed so fa is I now have the camera declare it's target in the Start function instead of in the Update. I also have it now so that my Game Master (which is always alive) instantiates the player, and THEN instantiates the camera, so there no NullReference about the camera not being able to find the player because he's not instantiated yet. Now what I'm noticing, is that the camera only jerks about when the player is running away from the camera. When strafing or running towards the camera the camera smoothly follows the player. Any ideas?
     
  7. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Alright, so growing impatient for responses I went through my Movement script piece by piece (commenting out lines and re-adding them little-by-little). The camera jerking back and forth doesn't start happening until I add in the anim.SetFloat("Speed", Input.GetAxis("Movement"))...any thoughts?
     
  8. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Maybe it's jerking because the motion isn't being smoothed by Time.deltaTime? You're transitioning directly from 0 to whatever the movement speed is, so there's a jerk before the camera puts itself back on the player head :D

    I dunno honestly, I don't use meccanim. Ever.