Restricting 2D Camera Zoom and Movement to an Image in Unity C#
The following code will allow you to constrain an orthographic 2D camera, so that it is always contained inside of a background image.
The script will calculate the movement constraints, as well as the max/min zoom values. Regardless of the aspect ratio, the camera will always stay within the image, therefore, never showing any bars on the top or sides of your scene.
The following image, is the demo running, while inside of Scene Mode, to give you an idea of how it works:
The source code is all contained in its own class. Read the comments for extra information:
using UnityEngine;
public class Camera2D : MonoBehaviour
{
//The background image to use
public Transform Area;
//Sprite details
private Sprite Sprite;
private float PixelUnits;
private Vector2 Size;
private Vector2 Offset;
//Camera bounds
private float Left;
private float Right;
private float Top;
private float Bottom;
private float MaxZoom;
private float MinZoom;
public void Start()
{
Sprite = Area.transform.GetComponent<SpriteRenderer>().sprite;
CalculatePixelUnits();
CalculateSize();
Refresh();
Center();
}
//Calculate the pixel per unit value is for this sprite
private void CalculatePixelUnits()
{
PixelUnits = Sprite.rect.width / Sprite.bounds.size.x;
}
//Calculate the size and offset of the background sprite
private void CalculateSize()
{
Size = new Vector2(Area.transform.localScale.x * Sprite.texture.width / PixelUnits,
Area.transform.localScale.y * Sprite.texture.height / PixelUnits);
Offset = Area.transform.position;
}
//Get zoom constraints, and zoom as large as possible for current view
private void Refresh()
{
//calculate current screen ratio
float w = Screen.width / Size.x;
float h = Screen.height / Size.y;
float ratio = w / h;
float ratio2 = h / w;
if (ratio2 > ratio)
{
MaxZoom = (Size.y / 2);
}
else
{
MaxZoom = (Size.y / 2);
MaxZoom /= ratio;
}
MinZoom = 1;
Camera.main.orthographicSize = MaxZoom;
RefreshBounds();
}
//Position the camera at the center of the background image
private void Center()
{
//set camera to center of background image
Vector2 position = Area.transform.position;
Vector3 camPosition = position;
Vector3 point = Camera.main.WorldToViewportPoint(camPosition);
Vector3 delta = camPosition - Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, point.z));
Vector3 destination = transform.position + delta;
transform.position = destination;
}
//Calculate the max distance the camera can travel
private void RefreshBounds()
{
var vertExtent = Camera.main.orthographicSize;
var horzExtent = vertExtent * Screen.width / Screen.height;
Left = horzExtent - Size.x / 2.0f + Offset.x;
Right = Size.x / 2.0f - horzExtent + Offset.x;
Bottom = vertExtent - Size.y / 2.0f + Offset.y;
Top = Size.y / 2.0f - vertExtent + Offset.y;
}
public void Update()
{
//You would typically hook into Refresh on a screen rotation or aspect ratio change
//In demo, we call it non stop to demonstrate the camera system
Refresh();
}
public void LateUpdate()
{
//Clamp camera inside of our bounds
Vector3 v3 = transform.position;
v3.x = Mathf.Clamp(v3.x, Left, Right);
v3.y = Mathf.Clamp(v3.y, Bottom, Top);
transform.position = v3;
}
public void Zoom(float value)
{
Camera.main.orthographicSize += value;
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize, MinZoom, MaxZoom);
}
}
The above script can be attached to a Orthographic Camera. The last thing you need to do is attach a GameObject that contains a SpriteRenderer to the newly added script:
You can also download a demo Unity project.
Github
Projects
Games
Articles
How would you change the code to work with a 3D object?