Search code examples
c#unity-game-enginecameralerp

Smooth move camera position according to array of cameras


I'm currently trying to smoothly change the camera's position using a pre-defined array of camera positions. It should go like this:

  • I press space, and the camera should smoothly change to the position of camera 0 in the camera array.
  • I press space again, and the camera should smoothly change to the position of camera 1 in the camera array
  • etc.

    public class CameraWaypoints : MonoBehaviour {
    
    public Camera[] CamPOVs;
    private Camera _main;
    private int _indexCurrentCamera;
    private int _indexTargetCamera;
    private float _speed = 0.1f;
    
    void Start () {
        _indexTargetCamera = 0;
        _main = Camera.main;
    
        //disable all camera's
        for (int i = 0; i < CamPOVs.Length; i++)
        {
            CamPOVs[i].enabled = false;
        }
    
        _indexCurrentCamera = 0;
    }
    
    // Update is called once per frame
    void Update () {
    
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (_indexTargetCamera < CamPOVs.Length)
            {
                _indexCurrentCamera = _indexTargetCamera;
                _indexTargetCamera++;
            }
        }
    
        //prevent array out of bounds
        if (_indexTargetCamera >= CamPOVs.Length)
        {
            _indexTargetCamera = 0;
        }
    
        _main.transform.position = Vector3.Lerp(CamPOVs[_indexCurrentCamera].transform.position, CamPOVs[_indexTargetCamera].transform.position, Time.time * _speed);
    
        _main.transform.rotation = CamPOVs[_indexTargetCamera].transform.rotation;
    
    
    }
    }
    

With my current solution, the camera actually smoothly moves to the target. HOWEVER, once that target is reached, on pressing space afterwards, the camera just changes to the target, without smoothing.

It's as if once the lerp has succesfully been completed once, it won't lerp ever again, unless I restart ofcourse.

EDIT: To clarify: when pressing space, the camera target actually changes, and the camera follows this target. The problem is that once the camera position has reached the target position once, it won't smoothly lerp to the target anymore, but rather change its position to the target immediately.


Solution

  • on pressing space afterwards, the camera just changes to the target, without smoothing.

    When you press space both source and target are changed so you're setting the transform's position immediately.

    once the lerp has succesfully been completed once, it won't lerp ever again, unless I restart ofcourse.

    From the doc:

    1. Time.time

    This is the time in seconds since the start of the game

    2. Vector3.Lerp

    The parameter t (time) is clamped to the range [0, 1]

    So, Time.time will continue to rise but Lerp will clamp to a maximum of 1. When you calculate Time.time * 0.1 (your speed) it'll take 10 seconds to reach your target. Anything over 10 seconds will be clamped to 1, which will result in an instant jump to your destination. Use Time.deltaTime instead.

    Additionally, you don't need multiple cameras just to act as positional targets. An array of transforms will be just fine.

    With all that said, here's how it should look:

    public class CameraWaypoints : MonoBehaviour
    {
        public Transform[] CamPOVs;
        public float _speed = 0.1f;
    
        private Camera _main;
        private int _indexTargetCamera;        
    
        void Awake ()
        {
            _main = Camera.main;
            _indexTargetCamera = 0;         
        }
    
        void Update ()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                _indexTargetCamera = ++_indexTargetCamera % CamPOVs.Length;
            }
    
             var time = Time.deltaTime * _speed;
    
             // Alternatives to Lerp are MoveTowards and Slerp (for rotation)  
             var position = Vector3.Lerp(_main.transform.position, CamPOVs[_indexTargetCamera].position, time);
             var rotation = Quaternion.Lerp(_main.transform.rotation, CamPOVs[_indexTargetCamera].rotation, time);
    
            _main.transform.position = position;
            _main.transform.rotation = rotation;
        }
    }