Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

[RESOLVED] Vector3.Lerp won't go from startMarker to endMarker smoothly

Discussion in '2D' started by Dommo1, Apr 30, 2020.

  1. Dommo1

    Dommo1

    Joined:
    Oct 28, 2018
    Posts:
    125
    Hi all

    At the beginning of my game scene the camera is zoomed in on the character. After a few seconds, the camera zooms out and you start playing.

    The character is on the left of the screen when zoomed out. I have zoom and the changing of the cameras position in the same script and this works fine (smoothly) in this part of the game.

    But now I am trying to basically reverse this when the character collides with an obstacle and the restart button appears. So the camera will move to the players position, then after a few seconds, zoom in.

    For the "End Zoom"... I have swapped the startMarker and endMarker around in the inspector (when compared to the "Start Zoom")... But the movement of the camera is instant rather than smooth. The zoom a few seconds later is fine though.

    Can anyone see what I am doing wrong? I really appreciate any suggestions!

    I have two versions of this script now while I have been playing with it so if you can see a fix/what I am doing wrong in either please let me know. I am very much a beginner so sorry if I am doing something hideously wrong! I have had a suggestion mentioned below.

    Thank you so much

    Version 1 - The issue might be that depending on when the restartButton activates, time has passed and the code that calculates the lerp percentage (fracJourney) is now larger than 1.0 and hence the end position:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraZoomEnd2 : MonoBehaviour
    6. {
    7.     //---------- ZOOM IN WHEN RESTART BUTTON APPEARS -----------
    8.     //Field of view target
    9.     public float TargetFOV = 54.00f;
    10.     //Will reach target value in 1sec. 2f will make it achieve in half second (1f/2f)... and so on
    11.     public float SpeedtoTarget = 1f;
    12.  
    13.  
    14.     //---------- CHANGING CAMERA POSITION ----------
    15.     // Transforms to act as start and end markers for the journey
    16.     public Transform startMarker;
    17.     public Transform endMarker;
    18.  
    19.     // Movement speed in units per second.
    20.     public float speed = 1.0F;
    21.  
    22.     // Time when the movement started.
    23.     private float startTime;
    24.  
    25.     // Total distance between the markers.
    26.     private float journeyLength;
    27.  
    28.     public float smooth = 5.0F;
    29.  
    30.     //-----------------------------------------------
    31.  
    32.     public GameObject cameraGameObject;
    33.     public GameObject restartButton;
    34.  
    35.  
    36.     // Use this for initialization
    37.     void Start()
    38.     {
    39.         // Time when the movement started.
    40.         startTime = Time.time;
    41.  
    42.         // Calculate the journey length.
    43.         journeyLength = Vector3.Distance(startMarker.position, endMarker.position);
    44.     }
    45.  
    46.     private float timer = 0;
    47.     private float timerMax = 0;
    48.  
    49.  
    50.     void Update()
    51.     {
    52.         if (restartButton.gameObject.activeSelf)
    53.  
    54.         {
    55.             //Disable ZOOM out script from start of scene
    56.             cameraGameObject.GetComponent<CameraZoomOutStart>().enabled = false;
    57.  
    58.             // Distance moved equals elapsed time, times speed..
    59.             float distCovered = (Time.time - startTime) * speed;
    60.  
    61.             // Fraction of journey completed equals current distance divided by total distance.
    62.             float fracJourney = distCovered / journeyLength;
    63.  
    64.             // Set our position as a fraction of the distance between the markers.
    65.             Camera.main.transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney);
    66.  
    67.             //Zoom in (field of view)
    68.             if (!Waited(1)) return;
    69.             Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, TargetFOV, SpeedtoTarget * Time.deltaTime);
    70.         }
    71.  
    72.     }
    73.  
    74.     private bool Waited(float seconds)
    75.     {
    76.         timerMax = seconds;
    77.  
    78.         timer += Time.deltaTime;
    79.  
    80.         if (timer >= timerMax)
    81.         {
    82.             return true; //max reached - waited x - seconds
    83.         }
    84.  
    85.         return false;
    86.     }
    87. }
    Version 2 - To try to resolve the issue with version 1, with the help of someone on another forum I have this:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraZoomEnd2 : MonoBehaviour
    6. {
    7.     //---------- ZOOM IN WHEN RESTART BUTTON APPEARS -----------
    8.     //Field of view target
    9.     public float TargetFOV = 54.00f;
    10.     //Will reach target value in 1sec. 2f will make it achieve in half second (1f/2f)... and so on
    11.     public float SpeedtoTarget = 1f;
    12.  
    13.  
    14.     //---------- CHANGING CAMERA POSITION ----------
    15.     // Transforms to act as start and end markers for the journey
    16.     public Transform startMarker;
    17.     public Transform endMarker;
    18.  
    19.     // Movement speed in units per second.
    20.     public float speed = 1.0F;
    21.  
    22.     // Time when the movement started.
    23.     private float startTime;
    24.  
    25.     // Total distance between the markers.
    26.     private float journeyLength;
    27.  
    28.     public float smooth = 5.0F;
    29.  
    30.     //-----------------------------------------------
    31.  
    32.     public GameObject cameraGameObject;
    33.     public GameObject restartButton;
    34.  
    35.     private bool lastState;
    36.  
    37.  
    38.     // Use this for initialization
    39.     void Start()
    40.     {
    41.  
    42.         lastState = restartButton.gameObject.activeSelf;
    43.     }
    44.  
    45.     private float timer = 0;
    46.     private float timerMax = 0;
    47.  
    48.  
    49.     void Update()
    50.     {
    51.         var currState = restartButton.gameObject.activeSelf;
    52.         if (currState && !lastState)
    53.         {
    54.             // state changed from false => true
    55.             startTime = Time.time;
    56.         }
    57.  
    58.         if (currState)
    59.         {
    60.             // Lerp in here!!!
    61.             //Disable ZOOM out script from start of scene
    62.             cameraGameObject.GetComponent<CameraZoomOutStart>().enabled = false;
    63.  
    64.  
    65.             // Distance moved equals elapsed time, times speed..
    66.             float distCovered = (Time.time - startTime) * speed;
    67.  
    68.  
    69.             // Fraction of journey completed equals current distance divided by total distance.
    70.             float fracJourney = distCovered / journeyLength;
    71.  
    72.  
    73.             // Set our position as a fraction of the distance between the markers.
    74.             Camera.main.transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney);
    75.  
    76.  
    77.             //Zoom in (field of view)
    78.             if (!Waited(1)) return;
    79.             Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, TargetFOV, SpeedtoTarget * Time.deltaTime);
    80.  
    81.             lastState = restartButton.gameObject.activeSelf;
    82.  
    83.         }
    84.  
    85.  
    86.  
    87.     }
    88.  
    89.     private bool Waited(float seconds)
    90.     {
    91.         timerMax = seconds;
    92.  
    93.         timer += Time.deltaTime;
    94.  
    95.         if (timer >= timerMax)
    96.         {
    97.             return true; //max reached - waited x - seconds
    98.         }
    99.  
    100.         return false;
    101.     }
    102. }
    But this gets this is the console which is apparently is often to do with dividing by 0:

    "transform.position assign attempt for 'Main Camera' is not valid. Input position is { NaN, NaN, NaN }. UnityEngine.Transform:set_position(Vector3) CameraZoomEnd2:Update() (at Assets/CameraZoomEnd2.cs:80)"

    Again, ANY help much appreciated!

    Thanks a lot
     
  2. nabrown

    nabrown

    Joined:
    Jun 27, 2019
    Posts:
    27
    To be clear, when the player loses you want the camera to pan back to the starting position of the level and then zoom in?

    You don't need fracJourney. The third parameter in Lerp is effectively the % of the total distance you want to move in a single frame. I think it'll work for you if you change it to

    float distPanned = Vector3.Distance(Camera.main.transform.position, endMarker.position);
    float fullDist = Vector3.Distance(endMarker.position, endMarker.position);
    float percPanned = distPanned / fullDist;
    percPanned += (Time.DeltaTime / PanSpeed);

    Vector3.Lerp(startMarker.position, endMarker.position, percPanned);


    Then you can just set PanSpeed to the total number of seconds you want the full pan to take. Not tested, but I think something like this should work.
     
  3. Dommo1

    Dommo1

    Joined:
    Oct 28, 2018
    Posts:
    125
    "To be clear, when the player loses you want the camera to pan back to the starting position of the level and then zoom in?" - Yes that's right mate.

    Thanks very much for your code, but I have encountered a NaN error in console again:

    "transform.position assign attempt for 'Main Camera' is not valid. Input position is { NaN, NaN, NaN }.
    UnityEngine.Transform:set_position(Vector3)
    CameraZoomEnd2:Update() (at Assets/CameraZoomEnd2.cs:44)"

    Although, firstly I may be implementing your code wrong (please forgive my ignorance - very much a beginner and struggling with this)... And secondly, if I keep the first zoom script active when the restartButton appears by commenting out this line:

    Code (CSharp):
    1. cameraGameObject.GetComponent<CameraZoomOutStart>().enabled = false;
    I don't get the NaN error anymore (but your version behaves the same way as the original - Sharp/instant switch of position).

    If you don't mind, could you please check that I have implemented your code the way you intended?:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraZoomEnd2 : MonoBehaviour
    6. {
    7.     //ZOOM:
    8.     //Field of view target
    9.     public float TargetFOV = 54.00f;
    10.     //(ZOOM) Will reach target value in 1sec. 2f will make it achieve in half second (1f/2f)... and so on
    11.     public float SpeedtoTarget = 1f;
    12.  
    13.     //CHANGE POSITION:
    14.     public Transform startMarker;
    15.     public Transform endMarker;
    16.     public float speed = 1.0F;
    17.  
    18.     public GameObject restartButton;
    19.     public GameObject cameraGameObject;
    20.  
    21.     public float PanSpeed = 30f;
    22.  
    23.  
    24.     // Use this for initialization
    25.     void Start()
    26.     {
    27.        
    28.     }
    29.  
    30.     private float timer = 0;
    31.     private float timerMax = 0;
    32.  
    33.  
    34.     void Update()
    35.     {
    36.         if (restartButton.gameObject.activeSelf)
    37.  
    38.         {
    39.  
    40.             float distPanned = Vector3.Distance(Camera.main.transform.position, endMarker.position);
    41.             float fullDist = Vector3.Distance(endMarker.position, endMarker.position);
    42.             float percPanned = distPanned / fullDist;
    43.             percPanned += Time.deltaTime / PanSpeed;
    44.             Camera.main.transform.position = Vector3.Lerp(startMarker.position, endMarker.position, percPanned);
    45.  
    46.             //cameraGameObject.GetComponent<CameraZoomOutStart>().enabled = false;
    47.  
    48.             if (!Waited(1)) return;
    49.             Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, TargetFOV, SpeedtoTarget * Time.deltaTime);
    50.         }
    51.  
    52.     }
    53.  
    54.     private bool Waited(float seconds)
    55.     {
    56.         timerMax = seconds;
    57.  
    58.         timer += Time.deltaTime;
    59.  
    60.         if (timer >= timerMax)
    61.         {
    62.             return true; //max reached - waited x - seconds
    63.         }
    64.  
    65.         return false;
    66.     }
    67. }
    And here is the other camera zoom script for the start of the scene just in case something is conflicting (although it is almost the same):

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraZoomOutStart : MonoBehaviour
    6. {
    7.    
    8.     //Field of view target
    9.     public float TargetFOV = 60.00f;
    10.  
    11.     //(ZOOM) Will reach target value in 1sec. 2f will make it achieve in half second (1f/2f)... and so on!
    12.     public float Speed = 1f;
    13.  
    14.     public Transform startMarker;
    15.     public Transform endMarker;
    16.     public float speed = 1.0F;
    17.     private float startTime;
    18.     private float journeyLength;
    19.     public float smooth = 5.0F;
    20.  
    21.  
    22.     //Obstacles enabled in awake:
    23.     public GameObject Obstacle;
    24.     public GameObject Wall;
    25.     public GameObject Ball;
    26.  
    27.  
    28.     //This is to allow move.cs to turn off on collision with player
    29.     public void Awake()
    30.     {
    31.         Obstacle.GetComponent<move>().enabled = true;
    32.         Wall.GetComponent<move>().enabled = true;
    33.         Ball.GetComponent<move>().enabled = true;
    34.     }
    35.  
    36.  
    37.     // Use this for initialization
    38.     void Start()
    39.     {
    40.         startTime = Time.time;
    41.         journeyLength = Vector3.Distance(startMarker.position, endMarker.position);
    42.     }
    43.  
    44.     private float timer = 0;
    45.     private float timerMax = 0;
    46.  
    47.    
    48.     void Update()
    49.     {
    50.         float distCovered = (Time.time - startTime) * speed;
    51.         float fracJourney = distCovered / journeyLength;
    52.         Camera.main.transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney);
    53.  
    54.         if (!Waited(4)) return;
    55.         Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, TargetFOV, Speed * Time.deltaTime);
    56.          
    57.     }
    58.  
    59.     private bool Waited(float seconds)
    60.     {
    61.         timerMax = seconds;
    62.  
    63.         timer += Time.deltaTime;
    64.  
    65.         if (timer >= timerMax)
    66.         {
    67.             return true; //max reached - waited x - seconds
    68.         }
    69.  
    70.         return false;
    71.     }
    72. }

    Thank you so much! Sorry to be a pain!
     
  4. Dommo1

    Dommo1

    Joined:
    Oct 28, 2018
    Posts:
    125
    I don't think I replied to your comment but rather I commented in the thread... Thanks for your help but I am still struggling with the same issue using your code (sharp change of camera position OR NaN error if I keep line 46 in the script - Which makes me think could be an issue of conflict with the first zoom script?)
     
  5. nabrown

    nabrown

    Joined:
    Jun 27, 2019
    Posts:
    27
    Try swapping the start and end position in the parameters, since your panning from the end to the start. As for NaN error you'll have to set a breakpoint there and see what isn't set. My guess would be start or end positions are messed up.
     
  6. Dommo1

    Dommo1

    Joined:
    Oct 28, 2018
    Posts:
    125
    Yes I did that in the inspector... So the first movement's startMarker is the second movement's endMarker and the first movement's endMarker is the 2nd movement's startMarker. I just tried them the other way around anyway but no joy.

    I might have to abandon this approach and try to find a different script or tutorial somewhere online.

    Thanks for all your help mate. much appreciated
     
  7. Dommo1

    Dommo1

    Joined:
    Oct 28, 2018
    Posts:
    125
    Anyone finding this is future and having similar issues... Nice easy alternative is just using an animation on the camera instead of lerp. Can't believe I just spent 2 days stuck on this and fixed it 5 minutes. Thanks for your help nabrown!