I\'m making a little arcade shooter for 2 players, and need to have the screen focused on 2 players, I got the camera moving in the center of the players in the X axis, but
jparimaa's answer helped me a lot, however it didn't work for me for narrow screens (e.g. phone portrait mode.) That's because it only accounts for height calculation, resulting in the two players being out of screen when they are close vertically but far horizontally.
I updated it to calculate camera distance correctly for height and width cases. The calculations are from Unity docs (same as jparimaa's):
The Size of the Frustum at a Given Distance from the Camera
Also note: Camera.fieldOfView is the vertical field of view
I ended up with the following code that works very well for my case: multiple space ships with 3D perspective camera that are controlled on 2D (x-z) plane:
using UnityEngine;
public class MeleeCamera : MonoBehaviour
{
public Transform[] targets;
public float padding = 15f; // amount to pad in world units from screen edge
Camera _camera;
void Awake()
{
_camera = GetComponent();
}
private void LateUpdate() // using LateUpdate() to ensure camera moves after everything else has
{
Bounds bounds = FindBounds();
// Calculate distance to keep bounds visible. Calculations from:
// "The Size of the Frustum at a Given Distance from the Camera": https://docs.unity3d.com/Manual/FrustumSizeAtDistance.html
// note: Camera.fieldOfView is the *vertical* field of view: https://docs.unity3d.com/ScriptReference/Camera-fieldOfView.html
float desiredFrustumWidth = bounds.size.x + 2 * padding;
float desiredFrustumHeight = bounds.size.z + 2 * padding;
float distanceToFitHeight = desiredFrustumHeight * 0.5f / Mathf.Tan(_camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
float distanceToFitWidth = desiredFrustumWidth * 0.5f / Mathf.Tan(_camera.fieldOfView * _camera.aspect * 0.5f * Mathf.Deg2Rad);
float resultDistance = Mathf.Max(distanceToFitWidth, distanceToFitHeight);
// Set camera to center of bounds at exact distance to ensure targets are visible and padded from edge of screen
_camera.transform.position = bounds.center + Vector3.up * resultDistance;
}
private Bounds FindBounds()
{
if (targets.Length == 0)
{
return new Bounds();
}
Bounds bounds = new Bounds(targets[0].position, Vector3.zero);
foreach (Transform target in targets)
{
if (target.gameObject.activeSelf) // if target not active
{
bounds.Encapsulate(target.position);
}
}
return bounds;
}
}