[Tutorial / Blog Post] Making a Orthographic Camera that Tracks Multiple Targets

Hey everyone,

I recently began working on a new top-down 2D local multiplayer game. One of my first goals was to get a decent camera system that would work well for a local game. My main goals were dynamic zooming to fit all players on screen, centering on all players, and supporting many targets simultaneously.

I managed to come up with a pretty simple orthographic camera system that seems to work pretty well and accomplish all these tasks. Like I said it’s simple, but it seems to work quite well. I couldn’t find any similar systems, so I figured I’d release the code and do a quick write-up explaning how it works. This may even be easy to adapt to a perspective camera, but I haven’t tried that yet.

Since it’s a moderately long post, I’m just going to provide a link to it. I’m hoping many of you find it useful, and you may even have ways to improve it. If you do feel free to post here or on the blog post itself. I’m happy to listen to any feedback.

The post is here: http://nielson.io/2014/03/making-a-target-tracking-orthographic-camera-in-unity/

Enjoy!

  • I originally posted this in scripting but I’ve since removed the links from there since this seems like the correct topic to post it under. Tried to delete the post so it doesn’t seem like spam but there doesn’t seem to be a remove post button.

I think your website is gone now. I found web archive and for someone looking his code here is this:

using UnityEngine;

public class TrackTargets : MonoBehaviour {

    [SerializeField]
    Transform[] targets;

    [SerializeField]
    float boundingBoxPadding = 2f;

    [SerializeField]
    float minimumOrthographicSize = 8f;

    [SerializeField]
    float zoomSpeed = 20f;

    Camera camera;

    void Awake ()
    {
        camera = GetComponent<Camera>();
        camera.orthographic = true;
    }

    void LateUpdate()
    {
        Rect boundingBox = CalculateTargetsBoundingBox();
        transform.position = CalculateCameraPosition(boundingBox);
        camera.orthographicSize = CalculateOrthographicSize(boundingBox);
    }

    /// <summary>
    /// Calculates a bounding box that contains all the targets.
    /// </summary>
    /// <returns>A Rect containing all the targets.</returns>
    Rect CalculateTargetsBoundingBox()
    {
        float minX = Mathf.Infinity;
        float maxX = Mathf.NegativeInfinity;
        float minY = Mathf.Infinity;
        float maxY = Mathf.NegativeInfinity;

        foreach (Transform target in targets) {
            Vector3 position = target.position;

            minX = Mathf.Min(minX, position.x);
            minY = Mathf.Min(minY, position.y);
            maxX = Mathf.Max(maxX, position.x);
            maxY = Mathf.Max(maxY, position.y);
        }

        return Rect.MinMaxRect(minX - boundingBoxPadding, maxY + boundingBoxPadding, maxX + boundingBoxPadding, minY - boundingBoxPadding);
    }

    /// <summary>
    /// Calculates a camera position given the a bounding box containing all the targets.
    /// </summary>
    /// <param name="boundingBox">A Rect bounding box containg all targets.</param>
    /// <returns>A Vector3 in the center of the bounding box.</returns>
    Vector3 CalculateCameraPosition(Rect boundingBox)
    {
        Vector2 boundingBoxCenter = boundingBox.center;

        return new Vector3(boundingBoxCenter.x, boundingBoxCenter.y, camera.transform.position.z);
    }

    /// <summary>
    /// Calculates a new orthographic size for the camera based on the target bounding box.
    /// </summary>
    /// <param name="boundingBox">A Rect bounding box containg all targets.</param>
    /// <returns>A float for the orthographic size.</returns>
    float CalculateOrthographicSize(Rect boundingBox)
    {
        float orthographicSize = camera.orthographicSize;
        Vector3 topRight = new Vector3(boundingBox.x + boundingBox.width, boundingBox.y, 0f);
        Vector3 topRightAsViewport = camera.WorldToViewportPoint(topRight);

        if (topRightAsViewport.x >= topRightAsViewport.y)
            orthographicSize = Mathf.Abs(boundingBox.width) / camera.aspect / 2f;
        else
            orthographicSize = Mathf.Abs(boundingBox.height) / 2f;

        return Mathf.Clamp(Mathf.Lerp(camera.orthographicSize, orthographicSize, Time.deltaTime * zoomSpeed), minimumOrthographicSize, Mathf.Infinity);
    }
}