Reputation: 13
I hope someone can help. Im trying to create a little script that zooms in to my player and back out - toggling. The zoom in works fine, but when I try to zoom back out it doesn't work, it gets stuck. I've created a bool to ensure it only runs the code when it needs to and I'm wondering if that is what's causing the error.
using UnityEngine;
using System.Collections;
public class CameraZoom : MonoBehaviour
{
public float zoom = 10f;
public float normal = 3.471398f;
public float smooth = 5f;
private bool isZoomed = false;
public Camera cam;
public GameObject player;
// lock the camera settings
public float LockedX = 0f;
public float LockedY = 0f;
public float LockedZ = 0f;
private bool hasBeenZoomed = false;
Vector3 targetPos;
private Transform playerTransform;
// Use this for initialization
void Start()
{
targetPos = transform.position;
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("z")) { isZoomed = !isZoomed; }
if (isZoomed == true)
{
ZoomInToPlayer();
hasBeenZoomed = true;
}
else
{
if (hasBeenZoomed)
{
ZoomOutFromPlayer();
hasBeenZoomed = false;
}
}
}
void ZoomInToPlayer()
{
// By default the target x and y coordinates of the camera are it's current x and y coordinates.
float targetX = transform.position.x;
float targetY = transform.position.y;
// ... the target x coordinate should be a Lerp between the camera's current x position and the player's current x position.
targetX = Mathf.Lerp(transform.position.x, playerTransform.position.x, smooth * Time.deltaTime);
//Debug.Log("player x is " + playerTransform.position.x + " and TargetX is " + targetX);
// ... the target y coordinate should be a Lerp between the camera's current y position and the player's current y position.
targetY = Mathf.Lerp(transform.position.y, playerTransform.position.y, smooth * Time.deltaTime);
//Debug.Log("player y is " + playerTransform.position.y+ " and TargetY is " + targetY);
// Set the camera's position to the target position with the same z component.
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// Change the size of the camera viewport
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, zoom, Time.deltaTime * smooth);
}
void ZoomOutFromPlayer()
{
// By default the target x and y coordinates of the camera are it's current x and y coordinates.
float targetX;
float targetY;
// Change the size of the camera viewport
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, normal, Time.deltaTime * smooth);
// ... the target x coordinate should be a Lerp between the camera's current x position and the original x position.
targetX = Mathf.Lerp(transform.position.x, LockedX, smooth * Time.deltaTime);
// ... the target y coordinate should be a Lerp between the camera's current y position and the original y position.
targetY = Mathf.Lerp(transform.position.y, LockedY, smooth * Time.deltaTime);
// Set the camera's position to the target position with the same z component.
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
}
}
Upvotes: 1
Views: 1677
Reputation: 51
Try this
using UnityEngine;
using System.Collections;
public class CameraZoom : MonoBehaviour
{
public float zoom = 10f;
public float normal = 3.471398f;
public float smooth = 5f;
private bool isZoomed = false;
private bool isZoomFinished = true; // the animation zoom is over ?
public Camera cam;
public GameObject player;
public float LockedX = 0f;
public float LockedY = 0f;
public float LockedZ = 0f;
private bool hasBeenZoomed = false;
Vector3 targetPos;
private Transform playerTransform;
void Start()
{
targetPos = transform.position;
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update()
{
if (Input.GetKeyDown("z") && isZoomFinished) {
isZoomed = !isZoomed;
isZoomFinished = false;
}
if (isZoomed && !isZoomFinished)
{
ZoomInToPlayer();
}
else if (!isZoomed && !isZoomFinished)
{
ZoomOutFromPlayer()
}
}
float delta = 0;
void ZoomInToPlayer()
{
delta += smooth * Time.deltaTime;
//Cam size
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, zoom, delta);
//Cam pos
float targetX = transform.position.x;
float targetY = transform.position.y;
targetX = Mathf.Lerp(transform.position.x, playerTransform.position.x, delta);
targetY = Mathf.Lerp(transform.position.y, playerTransform.position.y, delta);
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// is animation over ?
if(delta >= 1) {
isZoomFinished = true;
delta = 0;
}
}
void ZoomOutFromPlayer()
{
delta += smooth * Time.deltaTime;
//Cam size
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, normal, delta);
//Cam pos
float targetX;
float targetY;
targetX = Mathf.Lerp(transform.position.x, LockedX, delta);
targetY = Mathf.Lerp(transform.position.y, LockedY, delta);
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// is animation over ?
if(delta >= 1) {
isZoomFinished = true;
delta = 0;
}
}
}
Upvotes: 0
Reputation: 13297
Your methods ZoomInToPlayer
and ZoomOutFromPlayer
are written in a way that suggests that they should be called once per frame for the duration of the zoom in/out animation. However, ZoomOutFromPlayer
will only be called once, because Update
, when ZoomOutFromPlayer
is called, the hasBeenZoomed
is immediately set to false.
What you're trying to do here, essentially, is a simple Finite State Machine. I suggest researching this design pattern a little more — it will help you noticing the sources of such problems and structuring your code in a better way.
In this particular case, a good way to prevent this problem when designing your code would be to write something akin to "API documentation" for yourself, when writing your methods. For ZoomOutFromPlayer
, it would read something like this:
Call every frame when you want to perform zoom-out animation, until the animation is complete.
After you written (and read) such a description, you should immediately notice a red flag — "until the animation is complete"? So, the code that calls this method should somehow take track of whether the animation is complete or not, during a separate mechanism? Wouldn't it make it really easy to use this method incorrectly? Well, that's exactly what happened here.
Instead, what you could've done, is to create two different methods, ZoomInUpdate
and ZoomOutUpdate
, with descriptions that would read something like this:
Call every frame when the camera should be zoomed out/zoomed in.
This way, using this methods is a lot easier, and you can safely throw out additional logic with hasBeenZoomed
out. Just call these methods every frame, and ensure (inside these methods) that they change the camera settings with a certain speed, if these settings need to be changed, or otherwise do nothing.
Upvotes: 3