1

I'm new to Unity, transitioning from Unreal, and I'm trying to make a simple endless runner to start. I'm having trouble implementing the camera. I'm just trying to edit its camera distance variable in the body dropdown of its inspector via the player's speed variable. So as the player speeds up, the camera will slowly zoom out, and if they hit anything, the camera will zoom back in, due to their speed decreasing. The camera is a 2D cinemachine camera if that makes any difference. This is my current camera script:


public class CameraScript : MonoBehaviour
{
   public GameObject player;
   private float camDistance;
   private float zoom;
   private float camMax = 120f;
   private float camMin = 40f;
   [SerializeField] private float zoomSpeed = 10f;
   // Start is called before the first frame update
   void Start()
   {
       camDistance = GetComponent<Cinemachine.CinemachineVirtualCamera>().GetCinemachineComponent<Cinemachine.CinemachineFramingTransposer>().m_CameraDistance;
       InvokeRepeating("UpdateZoom", .5f, .5f);
   }

   // Update is called once per frame
   void Update()
   {

   }

   void UpdateZoom()
   {
       zoom = (player.GetComponent<MovementScript>().speed + 20);
       camDistance = Mathf.Lerp(camDistance, zoom, zoomSpeed);
       camDistance = Mathf.Clamp(camDistance, camMin, camMax);
       GetComponent<Cinemachine.CinemachineVirtualCamera>().GetCinemachineComponent<Cinemachine.CinemachineFramingTransposer>().m_CameraDistance = camDistance;
   }
}

I also tried using the script that is in UpdateZoom in Void Update, tried using Mathf.SmoothStep from this post:https://forum.unity.com/threads/camera-zoom-depending-on-object-speed.368169/ and tried using a coroutine based off of this script:

public class LerpMaterialColour : MonoBehaviour
{
   public Color targetColor = new Color(0, 1, 0, 1); 
   public Material materialToChange;
   void Start()
   {
       materialToChange = gameObject.GetComponent<Renderer>().material;
       StartCoroutine(LerpFunction(targetColor, 5));
   }
   IEnumerator LerpFunction(Color endValue, float duration)
   {
       float time = 0;
       Color startValue = materialToChange.color;
       while (time < duration)
       {
           materialToChange.color = Color.Lerp(startValue, endValue, time / duration);
           time += Time.deltaTime;
           yield return null;
       }
       materialToChange.color = endValue;
   }
}

from this article: https://gamedevbeginner.com/the-right-way-to-lerp-in-unity-with-examples/#lerp_rotation and I also used this video: https://www.youtube.com/watch?v=t4m8pmahbzY

All of my attempts only cause the camera to zoom out in instant increments like its teleporting or teleporting once to the max value. Here's a video of what it looks like with the current script: https://youtu.be/vXpNZZJkMN4

And here is my player script, I don't know if it might be part of the problem:

public class MovementScript : MonoBehaviour
{
   [SerializeField] LayerMask groundlayers;
   [SerializeField] private float JumpHeight = 10f;
   private float gravity = -50f;
   private Vector3 velocity;
   public CharacterController control;
   private bool isGrounded;
   // Start is called before the first frame update
   void Start()
   {
       control = GetComponent<CharacterController>();
       InvokeRepeating("IncreaseSpeed", .5f, .5f);
   }

   public CharacterController controller;
   [SerializeField] public float speed = 6;
   public float multiplier = 1;
   private float H_Input;

   // Update is called once per frame
   void Update()
   {
       //Adds gravity
       //Stops addition of gravity when grounded
       isGrounded = Physics.CheckSphere(transform.position, 3f/*2f causes sphere to be too high for jump detection*/, groundlayers, QueryTriggerInteraction.Ignore);
       if(isGrounded && velocity.y < 0)
       {
            velocity.y = 0;
       }
       else
       {
           velocity.y += gravity * Time.deltaTime;
       }
       control.Move(velocity * Time.deltaTime);

       //Adds constant forward movement
       H_Input = 1;
       control.Move(new Vector3(0, 0, H_Input) * Time.deltaTime * speed);

       //jump
       if (isGrounded && Input.GetButtonDown("Jump"))
       {
           velocity.y += Mathf.Sqrt(JumpHeight * -10 * gravity);
       }

   }

   void IncreaseSpeed()
   {
       //increases speed over time
       speed = speed + multiplier;
       multiplier = multiplier + 1f;
   }
}
GDBlue
  • 11
  • 1
  • Why the mixture of `[SerializeField] private` and `public` fields? If you already know how to do the former then don't use the latter. If your intent however is for _other_ scripts to access these members then change the `public` fields to properties with `public` getters and `private` setters. –  Aug 14 '22 at 22:22
  • Just me messing with it and learning how it works. As my post says, I'm still learning. – GDBlue Aug 15 '22 at 19:42

1 Answers1

0

Hi I stumbled on the same problem and here is my solution.

You need 4 variables namely maxSpeed,currentSpeed,maxZoom and minZoom

My solution requires a little bit of math but since I am not that good with maths myself I will try my best to explain.

Basically I divide Current Speed / Max Speed to get the Zoom Factor. for example if my Max Speed is 100 and current speed is 20 then Zoom Factor would be 0.2, so basically I need my camera to zoom out 20% of its original size.

Now that we have calculated how much we need to zoom, we can simply use linear interpolation between the minimum orthographic size and maximum orthographic size using Zoom Factor.

I hope you are familiar with linear interpolation if not, then no worries you can look up some articles here

https://learn.unity.com/tutorial/linear-interpolation

https://gamedevbeginner.com/the-right-way-to-lerp-in-unity-with-examples/

    void Update()
    {
        float zoomFactor = currentSpeed / maxSpeed;
        //I am using virtual camera but it should work with regular one as well.
        virtualCam.m_Lens.OrthographicSize = Mathf.Lerp(minZoom, maxZoom, zoomFactor);
    }
Mohak Jain
  • 1
  • 1
  • 1