AspectRatioEnforcer

Author: Eric Haines (Eric5h5)

Description
Forces the screen to a desired aspect ratio, using letterboxing/pillarboxing as needed. Includes functions that return corrected screen values for Screen.width/height and Input.mousePosition.

Usage
Put this script in a folder that compiles first, such as Standard Assets ( "Plugins" folder always compiles first ), so it can be accessed from Javascript and Boo, and call it AspectUtility. To use it, attach this script to your camera. It can also be attached to some other object, in which case it will attempt to find a camera tagged "Main Camera". For the WantedAspectRatio variable, enter the aspect ratio you want the camera to have. 4:3 is 1.333333, 16:10 is 1.6, and 16:9 is 1.777778, though any ratio can be used. If the aspect ratio is already the same as the desired one, nothing will happen. If the screen is less wide than the desired ratio, letterboxing with black bars will force a widescreen display. If the screen is more wide than the desired ratio, pillarboxing with black bars will force a more square display.

If letterboxing or pillarboxing is used, however, certain functions will no longer be correct. For one thing, Screen.width and Screen.height will still return values for the total screen size, not the new size of the main camera. This can potentially cause bad stuff to happen in your code. To compensate for that, you should use AspectUtility.screenWidth and AspectUtility.screenHeight instead. These are integers just like Screen.width and Screen.height, but are calculated based on the main camera's corrected ratio.

Similarly, Input.mousePosition also returns a value that's not appropriate for letterboxed/pillarboxed screens. Use AspectUtility.mousePosition instead, which will return a Vector3 with correct values. (It's true that only the x and y variables are used, but Input.mousePosition returns a Vector3 rather than Vector2, so the same is used for consistency.)

Note that these variables will not necessarily work if called in a script's Awake function. You should wait until Start or later to access them.

You can call the SetCamera function as necessary, such as when the screen size changes. For example, if you have a web player that uses a 4:3 aspect ratio window, and the user switches to full-screen mode that's 16:9, you'd want to call AspectUtility.SetCamera to set pillarboxing. You can check the screen's width and height to tell if a screen resolution change has occurred.

Usage with OnGUI
OnGUI code will need some extra work when used with AspectRatioEnforcer. OnGUI code is always drawn on top of everything, and is independent of all cameras, so it doesn't know how to use altered camera rects. The AspectUtility script has a few variables that can help, however.


 * screenRect

If you're using GUILayout code, you can use this in concert with GUILayout.BeginArea and EndArea to define a rect, and put all of your GUILayout code inside. For example, if you normally wrote this:

replace it with this instead:

If you were already using BeginArea/EndArea, it's fine to nest them, so this method will still work correctly.


 * xOffset and yOffset

If you're not using GUILayout, then you have to add an x and y offset to all rects. You can get these offsets with AspectUtility.xOffset and AspectUtility.yOffset. For example, if you normally wrote this:

replace it with this instead:

So all rects should have the xOffset and yOffset added to the x and y position.


 * guiMousePosition

Note that you should normally use Event.current.mousePosition in OnGUI code rather than Input.mousePosition. With AspectRatioEnforcer, you may want to use AspectUtility.guiMousePosition instead. This is mostly the same as Event.current.mousePosition, but will clamp the coordinates to the letterboxed/pillarboxed screen.

AspectUtilityEnhanced.cs
On Unity 3.5.2f2 there is an issue on iOS devices in which, even though only landscape orientation is enabled by the application developer, screen.width and screen.height are taken with the device assumed to be in portrait mode for some reason, that is a current aspect ratio of 0.667 detected when this script runs on iPhone for example. Here is a fixed version of the script that works on device and inside the Editor's preview window: