[SOLVED] Camera script auto zoom

Hi everybody ,

Sorry by advance for my bad english (i’m french).

I have a camera script from tank tutorial and i want make it auto zoom in and auto zoom out by the speed of the target .

for people who know like in GTA 1 on PSX , camera zoom out if you drive a vehicle and move fast and zoom in if you drive slowly.

here is a video and you can see camera effect :

and here is my script i want to edit :wink:

using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public float m_DampTime = 0.2f;                
    public float m_ScreenEdgeBuffer = 4f;          
    public float m_MinSize = 6.5f;                 
    public Transform[] m_Targets;
    public float playerSpeed;

    private Camera m_Camera;                       
    private float m_ZoomSpeed;                     
    private Vector3 m_MoveVelocity;                
    private Vector3 m_DesiredPosition;             


    private void Awake()
    {
        m_Camera = GetComponentInChildren<Camera>();
    }


    private void FixedUpdate()
    {
        Move();
        Zoom();
    }


    private void Move()
    {
        FindAveragePosition();

        transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
    }


    private void FindAveragePosition()
    {
        Vector3 averagePos = new Vector3();
        int numTargets = 0;

        for (int i = 0; i < m_Targets.Length; i++)
        {
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            averagePos += m_Targets[i].position;
            numTargets++;
        }

        if (numTargets > 0)
            averagePos /= numTargets;

        averagePos.y = transform.position.y;

        m_DesiredPosition = averagePos;
    }


    private void Zoom()
    {
        float requiredSize = FindRequiredSize();
        m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
    }


    private float FindRequiredSize()
    {
        Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);

        float size = 0f;

        for (int i = 0; i < m_Targets.Length; i++)
        {
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

            Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

            size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.y));

            size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.x) / m_Camera.aspect);
        }
       
        size += m_ScreenEdgeBuffer;

        size = Mathf.Max(size, m_MinSize);

        return size;
    }


    public void SetStartPositionAndSize()
    {
        FindAveragePosition();

        transform.position = m_DesiredPosition;

        m_Camera.orthographicSize = FindRequiredSize();
    }
}

can someone can help me please ?

Thanks by advance for your time.

anybody ? please :frowning:

Try the script below. It assumes the following:

  • You have a Player Object Somewhere, With a PlayerScript attached to it. That PlayerScript has a movement variable we can read. (You just need to change the names in my script to your specific ones)

  • You attach this script to your Orthographic Camera

  • You need to set some variables:

  • MinSize/MaxSize the minimum and maximum orthographic size for zooming. the default a camera starts at is 5.

  • MinSpeed/MaxSpeed These are the speeds that we care about for zooming in and out. If Max speed is set to 10, then any speed 10 or greater will Max Zoom Out. Same for min. If Min Speed is set to 3 any speed 3 or slower will be totally zoomed in.

  • ScaleTime = How long it should take to get from MaxZoom down to Min Zoom

  • Drag the Player Object onto the script

The script basically configures some mathy stuff at Start to know how fast to zoom in and out, and to what values.
Then each update, if its not in the middle of zooming in and out, it checks the player speed and if its not at the right zoom value, it starts a co-routine to change the zoom.

 // this is the time it takes the camera to go from max zoom to min zoom.
    public float scaleTime;
    public float maxSize;  // max zoom out size of our camera
    public float minSize;  // min zoom out size of our camera
    public float minSpeed;  // min speed the camera cares about.. this or slower = min Zoomout
    public float maxSpeed;  // the max speed our camera careas about.. this or faster = max zoomout
    public GameObject Player;

    private PlayerScript playerScript;
    private Camera camera;
    private bool isScaling;
    private float currentSize;
    private float targetSize;
    private float speedRange; // this is used for lerp function
    private float sizeDelta;  // how long it takes to change the camera size 1 unit;


    void Awake()
    {
        playerScript = Player.GetComponent<PlayerScript>();
        camera = GetComponent<Camera>();

        isScaling = false;
        currentSize = maxSize;
        speedRange = maxSpeed - minSpeed;
        sizeDelta = (maxSize - minSize) / scaleTime;
   
    }

    void Update()
    {
        // if we are currently scaling don't check movement
        if (isScaling)
            return;
        CheckSize(playerScript.speed);
    }

    void CheckSize(float speed)
    {
        // clamp our speed between min and max
        speed = Mathf.Clamp(speed, minSpeed, maxSpeed);
        // normalize the speed between a value of 0 and 1 for lerp
        speed = speed - minSpeed;  // this sets our speed in the range from 0->speedRange
        speed /= speedRange;  // now speed is Normalized between 0->1

        targetSize = Mathf.Lerp(minSize, maxSize, speed);
        if (targetSize != currentSize)
            StartCoroutine(ChangeSize());
    }

    IEnumerator ChangeSize()
    {

        bool zoomOut = false;
        if (currentSize < targetSize)
            zoomOut = true;
        if (currentSize > targetSize)
            zoomOut = false;
        isScaling = true;
        while (currentSize != targetSize)
        {
            if(zoomOut)
            {
                currentSize += sizeDelta * Time.deltaTime;
                if (currentSize > targetSize)
                    currentSize = targetSize;
            }
            else
            {
                currentSize -= sizeDelta * Time.deltaTime;
                if (currentSize < targetSize)
                    currentSize = targetSize;
            }
            camera.orthographicSize = currentSize;
            yield return null;
        }
        isScaling = false;
    }

Hi Takatok ,

Thanks a lot for your time , i really appreciate :wink:

I’ve try your script but when i run it nothing change :frowning:

i’m pretty sur i do something wrong :frowning:

here is my playerscript or the movement :

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {
    Animator animator;
    Animation animation;
    public float moveSpeed;
    private Rigidbody myRigidbody;
    private Vector3 moveInput;
    private Vector3 moveVelocity;
    private Camera mainCamera;
    public AnimationClip animationwalk;
    public GunController theGun;
    AudioSource audio;
    public AudioClip gunSound;

    public bool useController;
    public bool useGun;
    public bool walk;
    // Use this for initialization
    void Start () {
        myRigidbody = GetComponent<Rigidbody>();
        mainCamera = FindObjectOfType<Camera>();
        animator = GetComponent<Animator>();
        animation = GetComponent<Animation>();
        audio = GetComponent<AudioSource>();
        Cursor.visible = false;
    }
   
    // Update is called once per frame
    void Update () {
        moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
        moveVelocity = moveInput * moveSpeed;
        float h = 1;
        float v = 0;

        //Mouse Rotate
        if (!useController)
        {
            Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
            Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
            float rayLength;

            if (groundPlane.Raycast(cameraRay, out rayLength))
            {

                Vector3 pointToLook = cameraRay.GetPoint(rayLength);
                Debug.DrawLine(cameraRay.origin, pointToLook, Color.blue);
                transform.LookAt(new Vector3(pointToLook.x, transform.position.y, pointToLook.z));
            }

            if (Input.GetMouseButtonDown(0))
            {
                theGun.isFiring = true;
            }
            if (Input.GetMouseButtonUp(0))
            {
                theGun.isFiring = false;
            }
        }
        //Rotate with Controller
        if(useController)
        {
            Cursor.visible = false;
            Screen.lockCursor = true;
            Vector3 playerDirection = Vector3.right * Input.GetAxisRaw("RHorizontal") + Vector3.forward * -Input.GetAxisRaw("RVertical");
                if(playerDirection.sqrMagnitude > 0.0f)
                {
                transform.rotation = Quaternion.LookRotation(playerDirection, Vector3.up);
                }
            if (Input.GetButtonDown("Fire1"))
                theGun.isFiring = true;
            if (Input.GetButtonUp("Fire1"))
                theGun.isFiring = false;
            if (Input.GetAxisRaw("Fire") < 0.5f)
                theGun.isFiring = false;
            if (Input.GetAxisRaw("Fire") < 0.0f)
                theGun.isFiring = true;
        }
        else
        {
            Cursor.visible = false;
        }
        if (walk)
        {
            animator.SetFloat("walk", h);
        }
        else
        {
            animator.SetFloat("walk", v);
        }
}

    void FixedUpdate ()
    {
        myRigidbody.velocity = moveVelocity;
        Cursor.visible = false;
    }
}

i change from your scipt
CheckSize(playerScript.speed);
by
CheckSize(playerScript.moveSpeed);

any idea ?

It looks like your using moveSpeed as your multiplier for the input. Its a static variable that never changes.
moveVelocity is the actual velocity of your player. Add this to your code right before Start() function:

public float MoveSpeed {
        get { return Math.Max(moveVelocity.x,moveVelocity.y}
}

// then in my script change it to
CheckSize(playerScript.MoveSpeed);

This will add a Property field to your script. Currently either the horizontal or vertical speed, whichever is faster. Using a property is nice way to do it. Since my script will always just ask for MoveSpeed… and you can control what MoveSpeed returns. If say later you change how your player moves around you just change what MoveSpeed returns and the Camera script doesn’t need to be touched.

Also if you just want to make sure the Camera script works right change CheckSpeed to return a random number in the range that your speed should be:

void CheckSize(float speed)
    {
        //Put the number here that you need
         // make sure to take this back out if you want to link it to to your playerscript again
         return Random.Range(0,10.0);

         // rest of the CheckSize code would be here
    }

Thanks a lot i will try that :wink:

i’ve just test it and that much better now but

return Math.Max(moveVelocity.x, moveVelocity.z);

this work only if i go to right or up , the camera do nothing if i go on left or down with the player :frowning:

do you know what i need to edit ?

Its because down and left are negative velocity. Forgot about negative speeds so when you return a negative speed thats less than the MinSpeed in the camera script. We need to get the Absolute Value of the speed.

return Mathf.Max(Mathf.Abs(moveVelocity.x),Mathf.Abs(moveVelocity.y));

now is almost perfect but a problem persist
if the player move on diagonal the camera zoom-in little .
the max size for diagonal is not the same ?

Do you know why ?

it’s very annoying when you, play .

Whatever your move speed lets say its 5. When you move right your moving 5 to the right. When you move up your moving 5 up… but if you move up and right your moving 5*sqrt(2) diagonal. You moving faster going diagonally.

You can fix this by figuring out your max speed. Add this DebugLine to the Camera Code in CheckSize

// Add this Debug as the very first line of CheckSize
Debug.Log("CheckSpeed: Speed is " + speed.toString());

Move only up, or only right and you should see they are the same speed (or very close).
Now Move diagonal and you’ll see its bigger. Got to the Editor, Set MaxSpeed in the Camera Script to the only going up or rightspeed. Then if when your moving faster diagonally it won’t care. You can fiddle with MaxSpeed in the editor and it will adjust the most it will zoom out.

I just realized the above post is probably totally wrong. If the camera is zooming in, it means its going slower diagonally. Though it doesn’t make much sense. Since your just reporting the x,y components of the velocity. Still do the Debug.log and see what it reports for the Speed if your moving straight up, straight right and diagonal

i get this error :

Type float' does not contain a definition for toString’ and no extension method toString' of type float’ could be found (are you missing a using directive or an assembly reference?)

Take out the toString() I think unity will just convert it automatically by just having + speed);

the error was due to case sensitive ToString .

The result is the same speed for up or right or diagonal speed is 1.

i just find what’s wrong , if i play with the keyboard all is find speed is 1 diagonal or not but if i play with the gamepad the speed s between 0.5 and 0.99 that why when i change the direction the camera zoom in and zoom out .

I will try to change the input manager see if that solve the problem.

EDIT: I change the inputmanager sensitive and now all is fine :wink:

Thanks a lot for you’r time i really appreciate .

Now i need to setup for the car speed too .