Aspect ratio switching, Full Screen and Unity

As part of developing my game http://games4leap.com/rock-paper-scissors/, I had to deal with Aspect Ratio switching and going back and forth from full screen to other aspect ratios.

I found this wiki article on how to do this in Unity.
http://wiki.unity3d.com/index.php?title=AspectRatioEnforcer

This worked well for me for switching between aspect ratios in the editor and also at run-time, but I found that switching back and forth from FullScreen was an issue (it seemed that the aspect ratio does not get updated after the 1st switch?).  Anyhow, I modified the code so that it does 2 things I needed.

  1. Switches automatically if the aspect ratio changes
  2. Handles full screen switching well.

The other thing I made is change the backgroundCam.clearFlags to CameraClearFlags.Skybox instead of CameraClearFlags.SolidColor.  This way, you do not get the black rectangles at different aspect rations, but the skybox from the main skybox.  So, if you set the skybox to something matching your background, all is good.

Code Below – Just copy this into an AspectUtility.cs file and attach to your main camera (credit to initial AspectUtility as per link above)

 

using UnityEngine;
public class AspectUtility : MonoBehaviour {
    int lastScreenHeight  = 0;
    int lastScreenWidth  = 0;
    bool lastfullscreen = false;
    public float _wantedAspectRatio = 1.777778f; // (16:9)
    // public float _wantedAspectRatio = 1.3333333f; // 4:3
    public bool landscapeModeOnly = true;
    static public bool _landscapeModeOnly = true;
    static float wantedAspectRatio;
    static Camera cam;
    static Camera backgroundCam;

	void Awake () {
		Screen.fullScreen = true;
		_landscapeModeOnly = landscapeModeOnly;
        cam = camera;
        if (!cam) {
            cam = Camera.main;
			//Debug.Log ("Setting the main camera " + cam.name);
        }
		else {
			//Debug.Log ("Setting the main camera " + cam.name);
		}

        if (!cam) {
            //Debug.LogError ("No camera available");
            return;
        }
        wantedAspectRatio = _wantedAspectRatio;
        SetCamera();
	}

	void Update()
	{
		// check the screen height and witdh
		if ((Screen.height != lastScreenHeight) || (Screen.width != lastScreenWidth) || (Screen.fullScreen != lastfullscreen)) 
		{
			lastScreenWidth = Screen.width;
			lastScreenHeight = Screen.height;
			lastfullscreen = Screen.fullScreen;
			SetCamera();
		}
	}

    public static void SetCamera () {
		float currentAspectRatio = 0.0f;
		if(Screen.orientation == ScreenOrientation.LandscapeRight ||
			Screen.orientation == ScreenOrientation.LandscapeLeft) {
			//Debug.Log ("Landscape detected...");
        	currentAspectRatio = (float)Screen.width / Screen.height;
		}
		else {
			//Debug.Log ("Portrait detected...?");
			if(Screen.height  > Screen.width && _landscapeModeOnly) {
				currentAspectRatio = (float)Screen.height / Screen.width;
			}
			else {
				currentAspectRatio = (float)Screen.width / Screen.height;
			}
		}
        // If the current aspect ratio is already approximately equal to the desired aspect ratio,
        // use a full-screen Rect (in case it was set to something else previously)

		// Debug.Log ("currentAspectRatio = " + currentAspectRatio + ", wantedAspectRatio = " + wantedAspectRatio);

        if ((!Screen.fullScreen) && ((int)(currentAspectRatio * 100) / 100.0f == (int)(wantedAspectRatio * 100) / 100.0f)) 
		{
            cam.rect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
            if (backgroundCam) {
                Destroy(backgroundCam.gameObject);
            }
            return;
        }

        // Pillarbox
        if (currentAspectRatio > wantedAspectRatio) {
            float inset = 1.0f - wantedAspectRatio/currentAspectRatio;
            cam.rect = new Rect(inset/2, 0.0f, 1.0f-inset, 1.0f);
        }
        // Letterbox
        else {
            float inset = 1.0f - currentAspectRatio/wantedAspectRatio;
            cam.rect = new Rect(0.0f, inset/2, 1.0f, 1.0f-inset);
        }
        if (!backgroundCam) {
            // Make a new camera behind the normal camera which displays black; otherwise the unused space is undefined
            backgroundCam = new GameObject("BackgroundCam", typeof(Camera)).camera;
            backgroundCam.depth = int.MinValue;
            // backgroundCam.clearFlags = CameraClearFlags.SolidColor;
            backgroundCam.clearFlags = CameraClearFlags.Skybox;
            backgroundCam.backgroundColor = Color.black;
            backgroundCam.cullingMask = 0;
        }
    }

	public static int screenHeight {
		get {
			return (int)(Screen.height * cam.rect.height);
		}
	}

	public static int screenWidth {
		get {
			return (int)(Screen.width * cam.rect.width);
		}
	}

	public static int xOffset {
		get {
			return (int)(Screen.width * cam.rect.x);
		}
	}

	public static int yOffset {
		get {
			return (int)(Screen.height * cam.rect.y);
		}
	}

	public static Rect screenRect {
		get {
			return new Rect(cam.rect.x * Screen.width, cam.rect.y * Screen.height, cam.rect.width * Screen.width, cam.rect.height * Screen.height);
		}
	}

	public static Vector3 mousePosition {
		get {
			Vector3 mousePos = Input.mousePosition;
			mousePos.y -= (int)(cam.rect.y * Screen.height);
			mousePos.x -= (int)(cam.rect.x * Screen.width);
			return mousePos;
		}
	}

	public static Vector2 guiMousePosition {
		get {
			Vector2 mousePos = Event.current.mousePosition;
			mousePos.y = Mathf.Clamp(mousePos.y, cam.rect.y * Screen.height, cam.rect.y * Screen.height + cam.rect.height * Screen.height);
			mousePos.x = Mathf.Clamp(mousePos.x, cam.rect.x * Screen.width, cam.rect.x * Screen.width + cam.rect.width * Screen.width);
			return mousePos;
		}
	}
}