Search Unity

Smooth Follow Camera will always lag behind

Discussion in 'Scripting' started by RedHotFlashman, Nov 28, 2019.

  1. RedHotFlashman

    RedHotFlashman

    Joined:
    Mar 16, 2018
    Posts:
    35
    Hello,
    There are many posts about this, but I haven't found a suiting answer yet.
    I am making a side scrolling racing game like "Hill Climb Racing" or "MMX Hill Dash". The camera script is using the standard Lerp method on FixedUpdate.

    float damping = 0.2f;
    void UpdateCameraPosition(){
    Vector3 endPos = player.transform.position + offset;
    transform.position = Vector3.Lerp( transform.position, endPos, damping );
    }

    The problem is that the camera will never reach the endPosition until the vehicle stops. And as the vehicle goes faster, the camera will lag behind even further. What I want is a natural camera behavior as in real life. When the vehicle starts, the camera must lag behind, as if the cameraman is not fast enough to follow the starting movement of the car. But once the car is moving the cameraman has the car perfectly centered in view. And when the driver hits the brakes, the camera will overshoot at first, and then correct again.
    So somehow, I have figure out a way to set damping to zero, but I can't figure out a good solution because the speed and position of the vehicle is constantly changing.
    I am thinking to compare the velocity of the car and camera might be another solution, but how...?
     
    Last edited: Nov 28, 2019
  2. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,092
    Cinemachine is a great camera package available in the PackageManager. You can do all sorts of fancy camera effects. If you know how to use it, it can be quite the powerful tool
     
    RedHotFlashman likes this.
  3. RedHotFlashman

    RedHotFlashman

    Joined:
    Mar 16, 2018
    Posts:
    35
    Thx for the tip. But at first sight the problem stays. Damping actually is Lagging.
    They made a nice feature called LookAhead which could hide my problem if I would make that dynamic. But that still requires a logic solution with some kind of tweening. So I don't need a 6Mb pack when I just need five lines of code. Thx anyways, it is a nice package for a side scrolling game, but not the solution for a race game.
     
  4. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    Maybe try something like a spring camera. If you attach a spring to your car with the camera on the end of the spring then it would lag at first as the car accelerates. When the car reaches a constant velocity the spring would move back to follow the car exactly. When the car brakes the spring would overshoot too.

    I found this example but haven't tried it myself: https://github.com/anchan828/unity-...ls-(No Networking code)/SpringFollowCamera.cs
     
    RedHotFlashman likes this.
  5. RedHotFlashman

    RedHotFlashman

    Joined:
    Mar 16, 2018
    Posts:
    35
    Yes that is the idea, but the code you are providing doesn't seam to do that dynamically. When you pressed fire2 it will use ApplySnapping(), and by default it will ApplyPositionDamping() which uses SmoothDamp (which has the same problem as Lerp). So there is still no dynamic logic, it happens on a press of a button.
     
  6. VSM2018

    VSM2018

    Joined:
    Jun 14, 2018
    Posts:
    16
    Is your car movement also in FixedUpdate() ? Have you tryed LateUpdate() for the camera?
     
  7. RedHotFlashman

    RedHotFlashman

    Joined:
    Mar 16, 2018
    Posts:
    35
    I came up with a temporarly SOLUTION that works for me. The velocity and distance are tweened separately.

    // It is a 2.5D game this code handles camera X, the Y will work different.
    public float velocityDamping = 3f;
    public float catchUpDamping = 2f;

    void MoveCamX() {

    // Velocity
    targetVelocity = TargetX - prevTargetX;
    velocity = Mathf.Lerp( velocity, targetVelocity, velocityDamping * Time.deltaTime );

    // Catch Up
    float distToTarget = TargetX - CamX;
    dist = Mathf.Lerp( dist, distToTarget, catchUpDamping * Time.deltaTime );
    catchUpVelocity = dist * Time.deltaTime;

    // Set Camera X
    float newCamPos = CamX + velocity + catchUpVelocity;
    transform.position = new Vector3( newCamPos, Pos.y, Pos.z );

    // Set prev to get Velocity on next frame
    prevTargetX = TargetX;
    }

    Explanation:
    The velocity provides a momentum to make the elastic effect work, and the catchUpVelocity moves the camera back to target.
    Without the catchUpVelocity (catchUpDamping = 0f). At start, both camera and car are standing still, the car starts moving and slowly the camera starts moving to. After a few seconds the camera and vehicle have equal speeds, but the camera is far behind. So now we have to add a little bit of extra speed to catch up with the car.

    Work needed:
    While accelerating, the camera is still lagging, but not as much as the first version. This is fine for this game, but may change in the future. What is better in this version is, when top speed is reached the camera will center to the car, and this never happens in the first version, in the first version the camera would lag behind too far at high speeds.