Trying to add a Dead Zone to the Smooth Follow for an Isometric Camera

Hi guys, I’m still new to this so your sage advice is very welcome.

I’m trying to make a small isometric demo where the camera tracks the player at a fixed height and angle. So the SmoothFollow script with some of it’s rotation removed seemed ideal. Then I toyed with the idea of adding a dead zone in the middle of the screen to not have the camera constantly tracking.

Looking at the API I found camera.WorldToViewportPoint() which let me know how far to the left, right, up or down on the screen the character was. This seemed ideal so I wrapped the camera.transform updates from smooth follow into a conditional leaving a dead zone of 20% in the middle of the screen.

This seemed to work, the character could move within a small area before the script made the camera reposition itself to the same fixed distance and height from the player. However since the old script was meant to run every frame for a constant smooth motion, this offset difference cases a lurch as the camera jumps to reposition itself.

I was able to write a 2D camera controller dead zone, but had to do a bit of research to figure out how to get the camera to smoothly glide back to default orientation and follow the player. I’m afraid I don’t know where to look to get that effect here.

using UnityEngine;

public class SmoothFollow : MonoBehaviour {

// The target we are following
[SerializeField] private Transform target;
	
// The distance in the x-z plane to the target
[SerializeField] private float distance = 30.0f;
	
// the height we want the camera to be above the target
[SerializeField] private float height = 45.0f;
[SerializeField] private float heightDamping;

Camera camera;


void Start () {
	camera = GetComponent<Camera>();
}
	
void LateUpdate()
{
	// Early out if we don't have a target
	if (!target)
		return;

	// Calculate the current height
	var wantedHeight = target.position.y + height;
	var currentHeight = transform.position.y;

	Vector3 viewPos = camera.WorldToViewportPoint(target.position);

	if (viewPos.x > 0.6F || viewPos.x < 0.4F || viewPos.y < 0.4F || viewPos.y > 0.6F) {
		// Damp the height
		currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

		float targetX = transform.position.x;
		float targetZ = transform.position.z;
		
		// Set the position of the camera on the x-z plane to:
		// distance meters behind the target
		transform.position = target.position;
		transform.position -= Vector3.forward * distance;
		
		// Set the height of the camera
		transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);
		
		// Always look at the target
		transform.LookAt(target);
	}

}

}

This is mostly the stock script with a few references to the rotation removed since it’s an isometric game. I’m sure the logic here is sound, but how to get the camera to glide over to the player or consistently chase him if he is outside the 20% dead zone till he’s centered once more is the key. Easy with a orthographic camera, harder for me with an isometric.

Thank you for any help or links you can provide to help!

One thing you could do is to, instead of only executing the code if the player is outside the dead zone, to trigger a coroutine(or toggle a bool that enables something in the LateUpdate code) once the player is outside it, but nothing more. Then you can have the camera moveto the player until it is on top of the player(wiht a small margin), and then toggle the bool off(or end the coroutine).
This is of course if I didnt completely misunderstand your question :slight_smile:

Ok so I was able to use the coroutine method to create a coroutine that takes the desired location after calculating the offsets, passes it to the coroutines vertex.lerp and only moves the camera when the player is outside the bounds of the dead zone.

using UnityEngine;
using System.Collections;

public class SmoothFollow : MonoBehaviour {

[SerializeField] 
private Transform target; // The target we are following
	
[SerializeField] 
private float distance = 30.0f; // The distance in the x-z plane to the target
	
[SerializeField] 
private float height = 45.0f; // the height we want the camera to be above the target

[SerializeField] 
private float heightDamping;
private Camera mainCam;

public float transitionDuration = 2.5f; 


void Start () {
	mainCam = GetComponent<Camera>();
}

void OnGUI() {
	GUI.Button(new Rect(Screen.width/4, Screen.height/4, Screen.width/2, Screen.height/2), "Dead Zone");
}

void LateUpdate() {

	if (!target)
		return;

	Vector3 viewPos = mainCam.WorldToViewportPoint(target.position); // Assign the coordinates of the target to viewPos in Viewport space

	if (viewPos.x >= 0.75F || viewPos.x <= 0.25F || viewPos.y <= 0.25F || viewPos.y >= 0.75F) // Check if the target is beyond the boundaries defined for the dead zone
		StartCoroutine(Transition()); // If the target is on or outside the boundary, move the camera to recenter on it

}

IEnumerator Transition() {
	
	Vector3 targetPos = Vector3.zero;
	float t = 0.0f; 
	Vector3 startingPos = transform.position; 
	var wantedHeight = target.position.y + height;
	var currentHeight = transform.position.y;
	
	while (t < 0.50f) { 
		t += Time.deltaTime * (Time.timeScale/transitionDuration); // set the duration of the camera lerp in seconds
		currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime); //Lerp currentHeight with the camera's desired height over time
		targetPos = target.position; // Set the targetPos of the camera to the xyz of the character
		targetPos -= Vector3.forward * distance; // Add the distance offset to the character in the targetPos's forward facing (Positive Z)
		targetPos = new Vector3(targetPos.x, currentHeight, targetPos.z); // Replace the Y of the targetPos with the value in currentHeight
		
		transform.position = Vector3.Lerp(startingPos, targetPos, t); // Vertex.Lerp the camera from startingPos -> targetPos over time
		yield return 0;
	}
}

}

Only issue I have is if the character moves on a ramp, the camera is too slow to raise it’s Y elevation to match his and if he moves for too long he can even outpace the camera since it’s transition time is set for 2 seconds for a smooth transition.

I’m still unclear why a method written to pass the values to a lerp made the camera jump to the target location rather than glide over and a coroutine works. I’d love to learn the answer to that one.