Update: This script has been superseded by AC v1.72.1, which allows you to define a "Background contraint" in a GameCamera 2D, which will act as the boundary limits.
Original post below:
This script changes the Horizontal and Vertical constrain values of a GameCamera2D based on the current aspect ratio, in an effort to ensure the percieved "edge" of the scene is constant for all devices and resolutions.
It works by taking constrain values when the aspect ratio is both 16:9 and 4:3, and interpolates between them based on the actual aspect ratio.
To use it:
- Copy the code below into a new C# file named DynamicCameraLimits.cs, and attach it to a GameCamera2D.
- Run the game and set the aspect ratio (via the top of the Game Window) to 4:3. Then adjust the component's "Four By Three" values - where X is the minimum limit for a given direction, and Y is the maximum.
- Change the aspect ratio to 16:9, and adjust the component values again.
- Copy the component values, exit play mode, and paste them back in.
This script likely won't work for "extreme" aspect ratios (e.g. 2), but the script could likely be extended to incoprorate an array of CameraLimits to allow for interpolation between multiple ratios.
using UnityEngine;
using System.Collections;
using AC;
[RequireComponent (typeof (GameCamera2D))]
public class DynamicCameraLimits : MonoBehaviour
{
#region Variables
[SerializeField] private CameraLimits fourByThree = new CameraLimits (1.333f);
[SerializeField] private CameraLimits sixteenByNine = new CameraLimits (1.778f);
private GameCamera2D gameCamera2D;
#endregion
#region UnityStandards
private void OnEnable ()
{
gameCamera2D = GetComponent <GameCamera2D>();
EventManager.OnUpdatePlayableScreenArea += OnUpdatePlayableScreenArea;
}
private void OnDisable ()
{
EventManager.OnUpdatePlayableScreenArea -= OnUpdatePlayableScreenArea;
}
#endregion
#region PrivateFunctions
private void OnUpdatePlayableScreenArea ()
{
float aspectRatio = GetAspectRatio ();
if (gameCamera2D.limitHorizontal)
{
Vector2 hLimits = GetLimits (aspectRatio, true);
gameCamera2D.constrainHorizontal = hLimits;
}
if (gameCamera2D.limitVertical)
{
Vector2 vLimits = GetLimits (aspectRatio, false);
gameCamera2D.constrainVertical = vLimits;
}
}
private float GetAspectRatio ()
{
Vector2 windowSize = ACScreen.safeArea.size;
return windowSize.x / windowSize.y;
}
private Vector2 GetLimits (float aspectRatio, bool isHorizontal)
{
Vector2 fourByThreeLimits = (isHorizontal) ? fourByThree.horizontalLimits : fourByThree.verticalLimits;
Vector2 sixteenByNineLimits = (isHorizontal) ? sixteenByNine.horizontalLimits : sixteenByNine.verticalLimits;
float minGradient = (sixteenByNineLimits.x - fourByThreeLimits.x) / (sixteenByNine.AspectRatio - fourByThree.AspectRatio);
float minIntercept = fourByThreeLimits.x - (minGradient * fourByThree.AspectRatio);
float maxGradient = (sixteenByNineLimits.y - fourByThreeLimits.y) / (sixteenByNine.AspectRatio - fourByThree.AspectRatio);
float maxIntercept = fourByThreeLimits.y - (maxGradient * fourByThree.AspectRatio);
Vector2 newLimits = new Vector2 (minIntercept, maxIntercept) + new Vector2 (minGradient * aspectRatio, maxGradient * aspectRatio);
return newLimits;
}
#endregion
#region PrivateClasses
[System.Serializable]
private class CameraLimits
{
public Vector2 horizontalLimits, verticalLimits;
private float aspectRatio;
public CameraLimits (float aspectRatio)
{
this.aspectRatio = aspectRatio;
horizontalLimits = verticalLimits = Vector2.zero;
}
public float AspectRatio
{
get
{
return aspectRatio;
}
}
}
#endregion
}