How to handle different aspect ratios in unity: a complete guide

Cover Blog

Like the 12 labours of Hercules, handling different aspect ratios in unity is a hard feature to achieve.

It’s difficult because there are many possibilities and different things to consider.

The goal today is to let you better understand what is important to remember.

Because it’s quite easy to make mistakes or choose the wrong way to handle different aspect ratios in Unity. 

Besides this, I’m going to show you some helpful implementations that will help you to quickly and easily solve this difficult labour!

I will talk about a 2D world, but basically you can consider the same concepts as basics for a 3D world too!

Ok then what are we waiting for? Let’s go!

Aspect Ratios in Unity and in General

Aspect ratio

Now we have to consider the aspect ratio. First of all we should find an aspect ratio that could fit to design our game. We can choose our desired aspect ratio or we can alternatively pick one of the most used ones: like 16:9 for landscape games.

Aspect ratio is the result of width/height division. 16:9 means 16/9 = 1,77777777777777778.

The important thing is to respect the chosen aspect ratio, then it’s not important the resolution, but if we divide width and height we should obtain the same result.

Let me give you an example:

1024×576, 1280×720 (HD), 1366×768, 1920×1080 (Full HD), 2048×1152 are 16:9 it means that the result of width/height will be the same. Try yourself and check if I’m right.

So this is the first thing to consider, choose an aspect ratio and a resolution and maintain it to design your game. It will be your “target” or “reference” aspect ratio and resolution.

You can see which aspect ratio you are working on in the game tab.

Reference Target Resolution

The 3 main areas for handling aspect ratios in Unity

Areas of interest

Now we know that we should decide a target aspect ratio to work on, keeping in mind that in different resolutions we could load different Asset bundles to save memory. It’s time to handle different aspect ratios to let our game work on different devices.

There are 2 main areas to consider:

  • Game Elements
  • UI Elements

And 1 that is not as important as the first 2, but I want to tell you about it:

  • Backgrounds 

Aspect Ratios Unity: Game Elements

Game elements

Game elements are all the game objects we have in our scenes. To easily understand what I’m talking about consider all the objects with sprites except the ones in the Canvas object.

CAMERA

The camera does all the hard work. If you try to change the different aspect ratio you will notice that unity keeps the height of the game, but not the width. It affects quite a lot of your game in different aspect ratios.

Lucky for you I have a special script to let you do this and see in real time what happens in the editor.

/* The MIT License (MIT)

Copyright (c) 2014, Marcel Căşvan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

using System;
using System.Collections;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent (typeof (Camera))]
public class CameraFit : MonoBehaviour
{
	#region FIELDS
	public float UnitsForWidth = 1; // width of your scene in unity units
	public static CameraFit Instance;
	
	private float _width;
	private float _height;
	//*** bottom screen
	private Vector3 _bl;
	private Vector3 _bc;
	private Vector3 _br;
	//*** middle screen
	private Vector3 _ml;
	private Vector3 _mc;
	private Vector3 _mr;
	//*** top screen
	private Vector3 _tl;
	private Vector3 _tc;
	private Vector3 _tr;
	#endregion
	
	#region PROPERTIES
	public float Width {
		get {
			return _width;
		}
	}
	public float Height {
		get {
			return _height;
		}
	}
	
	// helper points:
	public Vector3 BottomLeft {
		get {
			return _bl;
		}
	}
	public Vector3 BottomCenter {
		get {
			return _bc;
		}
	}
	public Vector3 BottomRight {
		get {
			return _br;
		}
	}
	public Vector3 MiddleLeft {
		get {
			return _ml;
		}
	}
	public Vector3 MiddleCenter {
		get {
			return _mc;
		}
	}
	public Vector3 MiddleRight {
		get {
			return _mr;
		}
	}
	public Vector3 TopLeft {
		get {
			return _tl;
		}
	}
	public Vector3 TopCenter {
		get {
			return _tc;
		}
	}
	public Vector3 TopRight {
		get {
			return _tr;
		}
	}
	#endregion
	
	#region METHODS
	private void Awake()
	{
		try{
			if((bool)GetComponent()){
				if (GetComponent().orthographic) {
					ComputeResolution();
				}
			}
		}catch (Exception e){
			Debug.LogException(e, this);
		}
	}
	
	private void ComputeResolution()
	{
        float deviceWidth;
		float deviceHeight;
		float leftX, rightX, topY, bottomY;
#if UNITY_EDITOR
        deviceWidth = GetGameView().x;
		deviceHeight = GetGameView().y;
#else
		deviceWidth = Screen.width;
		deviceHeight = Screen.height;
#endif
   
		/* Set the ortograpish size (shich is half of the vertical size) when we change the ortosize of the camera the item will be scaled 
		 * autoamtically to fit the size frame of the camera
		 */
		GetComponent().orthographicSize = 1f / GetComponent().aspect * UnitsForWidth / 2f;

		//Get the new height and Widht based on the new orthographicSize
		_height = 2f * GetComponent().orthographicSize;
		_width = _height * GetComponent().aspect;
		
		float cameraX, cameraY;
		cameraX = GetComponent().transform.position.x;
		cameraY = GetComponent().transform.position.y;
		
		leftX = cameraX - _width / 2;
		rightX = cameraX + _width / 2;
		topY = cameraY + _height / 2;
		bottomY = cameraY - _height / 2;
		
		//*** bottom
		_bl = new Vector3(leftX, bottomY, 0);
		_bc = new Vector3(cameraX, bottomY, 0);
		_br = new Vector3(rightX, bottomY, 0);
		//*** middle
		_ml = new Vector3(leftX, cameraY, 0);
		_mc = new Vector3(cameraX, cameraY, 0);
		_mr = new Vector3(rightX, cameraY, 0);
		//*** top
		_tl = new Vector3(leftX, topY, 0);
		_tc = new Vector3(cameraX, topY , 0);
		_tr = new Vector3(rightX, topY, 0);
		Instance = this;
	}
	
	private void Update()
	{
		#if UNITY_EDITOR
		ComputeResolution();
		#endif
	}
	
	private void OnDrawGizmos()
	{
		if (GetComponent().orthographic) {
			DrawGizmos();
		}
	}
	
	private void DrawGizmos()
	{
		//*** bottom
		Gizmos.DrawIcon(_bl, "point.png", false);
		Gizmos.DrawIcon(_bc, "point.png", false);
		Gizmos.DrawIcon(_br, "point.png", false);
		//*** middle
		Gizmos.DrawIcon(_ml, "point.png", false);
		Gizmos.DrawIcon(_mc, "point.png", false);
		Gizmos.DrawIcon(_mr, "point.png", false);
		//*** top
		Gizmos.DrawIcon(_tl, "point.png", false);
		Gizmos.DrawIcon(_tc, "point.png", false);
		Gizmos.DrawIcon(_tr, "point.png", false);
		
		Gizmos.color = Color.green;
		Gizmos.DrawLine(_bl, _br);
		Gizmos.DrawLine(_br, _tr);
		Gizmos.DrawLine(_tr, _tl);
		Gizmos.DrawLine(_tl, _bl);
	}
	
	private Vector2 GetGameView()
	{
		System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
		System.Reflection.MethodInfo getSizeOfMainGameView =
			T.GetMethod("GetSizeOfMainGameView",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
		System.Object resolution = getSizeOfMainGameView.Invoke(null, null);
		return (Vector2)resolution;
	}
	#endregion
}

 In particular there is just a main parameter we can work with to adjust our game from a standard aspect ratio we chose before:

  • Pixels to Units

This is about how many pixels to units we would like to visualise.

Adjusting this parameter will affect the size of the rectangle of the Camera. 

  • So the first thing is to check if we are in the target aspect ratio chosen before (1).
  • Then select the camera (2) and add this script to the camera (3).
  • Then with the Game tab opened, just change the parameter (4). The camera will start adjusting its size, we should set the parameter until we are satisfied with the size of the camera.

Add Camera Fit Script

Once found the desired size we can switch in different resolutions and check what happens.

Everything is fitting in the right way for all the resolutions. Amazing!

ANCHORS

Now we should solve another issue, the things are scaled by the width and look nice, but in some aspect ratios we see that the ground is not anymore in the bottom for instance.

To solve this we can use another script to anchor the object to the camera!

This is the script:

/***
 * This script will anchor a GameObject to a relative screen position.
 * This script is intended to be used with CameraFit.cs by Marcel Căşvan, available here: http://gamedev.stackexchange.com/a/89973/50623
 * 
 * Note: For performance reasons it's currently assumed that the game resolution will not change after the game starts.
 * You could not make this assumption by periodically calling UpdateAnchor() in the Update() function or a coroutine, but is left as an exercise to the reader.
 */
/* The MIT License (MIT)

Copyright (c) 2015, Eliot Lash

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
using UnityEngine;
using System.Collections;
using UnityEditor;

[ExecuteInEditMode]
public class CameraAnchor : MonoBehaviour
{
    public enum AnchorType
    {
        Undefined,
        BottomLeft,
        BottomCenter,
        BottomRight,
        MiddleLeft,
        MiddleCenter,
        MiddleRight,
        TopLeft,
        TopCenter,
        TopRight,
    };

    private Vector3 standardPosition;
    public AnchorType anchorType;
    public Vector3 anchorOffset;

    // Use this for initialization
    void Start()
    {
#if UNITY_EDITOR
        if (!EditorApplication.isPlaying && anchorType == AnchorType.Undefined)
        {
            standardPosition = transform.position;
        }
        else
        {
            Vector3 newPos = GetAnchorVector() + anchorOffset;
            standardPosition = transform.position - newPos;
        }

#endif
#if !UNITY_EDITOR
        Vector3 newPos = GetAnchorVector() + anchorOffset;
        standardPosition = transform.position - newPos;
#endif


        UpdateAnchor();
    }

    Vector3 GetAnchorVector()
    {
        Vector3 anchor = Vector3.zero;
        switch (anchorType)
        {
            case AnchorType.BottomLeft:
                anchor = CameraFit.Instance.BottomLeft;
                break;
            case AnchorType.BottomCenter:
                anchor = CameraFit.Instance.BottomCenter;
                break;
            case AnchorType.BottomRight:
                anchor = CameraFit.Instance.BottomRight;
                break;
            case AnchorType.MiddleLeft:
                anchor = CameraFit.Instance.MiddleLeft;
                break;
            case AnchorType.MiddleCenter:
                anchor = CameraFit.Instance.MiddleCenter;
                break;
            case AnchorType.MiddleRight:
                anchor = CameraFit.Instance.MiddleRight;
                break;
            case AnchorType.TopLeft:
                anchor = CameraFit.Instance.TopLeft;
                break;
            case AnchorType.TopCenter:
                anchor = CameraFit.Instance.TopCenter;
                break;
            case AnchorType.TopRight:
                anchor = CameraFit.Instance.TopRight;
                break;
            case AnchorType.Undefined:
                anchor = Vector3.zero;
                break;
        }
        return anchor;
    }

    void UpdateAnchor()
    {
        Vector3 anchorVector = GetAnchorVector();
        SetAnchor(anchorVector);
    }

    void SetAnchor(Vector3 anchor)
    {
        Vector3 newPos = anchor + anchorOffset;
        if (!transform.position.Equals(standardPosition + newPos))
        {
            transform.position = standardPosition + newPos;
        }
    }


    // Update is called once per frame
#if UNITY_EDITOR
    void Update()
    {
        if (!EditorApplication.isPlaying)
            UpdateAnchor();


    }
#endif
}

We can attach this script to all the objects we want to anchor somewhere to the camera.

  • Always in the target aspect ratio, just select all the game objects we want to anchor in a certain point of the camera (1).
  • Then attach the script Camera Anchor (2)
  • Set the anchor point of the camera (3), you will notice everything will move away from the point it was before.
  • Adjust with the new position through the parameter (4), the objects will move according to it.
  • Repeat this action to anchor all the objects to the different anchor points of the camera if needed.

Camera Anchors Script

Well now we can repeat again the test of changing aspect ratio:

Now the ground is always in the bottom, so we reached our goal, it just remains to take care of the background!

Aspect Ratios Unity: Backgrounds

Backgrounds

I just want to spend a few words on backgrounds because usually, having a surplus of images is the best way typically for such background elements.

These background elements, being bigger than the game area, could save us in different resolutions to see some nice images instead of black bars.

So the first thing to do is in our target aspect ratio check if the background we placed is bigger than the camera size, please keep in mind, the background should be always visible with different camera sizes.

Then we can use the anchor script to anchor it to the center of the camera.

  • Again select the background object in the scene (1)
  • Add the anchor script (2)
  • Set the anchor point as “Middle Center” (3)
  • Adjust the position if necessary (4)

Background anchor

Now we are ready to check the final result.

I think we are pretty satisfied now. Our game is ready to handle different aspect ratios!

Aspect Ratios Unity: UI

UI

One last important area to discuss is the UI.

UI is the user interface and in Unity it includes all the elements we can add grouped under UI, like a button or a text for instance.

UI ANCHORS

Unity uses Canvas objects to design the UI in a game. We are really lucky because it provides a similar system we used before, but visual to anchor all UI elements to the screen.

  • So we should just add a UI component (1)
  • Select the UI component (2)
  • Select the Anchor quadrant (3)
  • Decide where anchor our element (4)
  • Obviously we can edit the size, position of the element etc…

UI Canvas Anchors

Once placed all the elements we can see what happens now:

The anchors are kept, but the UI looks a bit weird, because there is no resize of the elements.

Unity thought about it and gave us a special component to solve the problem: Canvas Scaler.

CANVAS SCALER

It should be already attached to the Canvas, if not you can easily add it by searching it through the components.

  • Select the Canvas (1)
  • Check the Canvas Scaler component in the right
  • Set the UI Scale Mode in “Scale With Screen” (2)
  • Do you remember the reference resolution you chose in the beginning with the aspect ratio? Set it here. (3)
  • Set the “Match” value to 0.5 (4)

Canvas Scaler

Obviously you can check the documentation or play with these parameters to find different strategies depending on what you want to do. I just showed you the common settings.

Let’s see in the end our result.

We definitely did it!

Conclusion

This was a really hard job! Maths, scripts, parameters a lot of stuff, but we worked it out together.

I know it’s a bit hard, but this is an important aspect to consider because without handling different aspect ratios, it will be hard for you to release your game!

Let’s recap what we have to to do handle different aspect ratios in Unity:

  • Choose a resolution and its aspect ratio as a target to design our game.
  • Add the CameraFit script to the Camera to let game elements resize by width.
  • Add the Camera Anchor script to all the game objects we want to anchor to a point in the camera.
  • Check if the backgrounds are big enough to always fit the camera size
  • Set the anchor points of UI elements when we add to the Canvas
  • Set the Canvas Scaler component and adjust its parameters

If you want to understand more behind Unity, you could find interesting Unity Collision Detection 2D Everything You Need To Know + Examples or Unity Raycast 2D What Is It And How To Use It.

This is it! I hope you found this article helpful, see you for the next challenge!

More from Romeo Violini

Gamification – What is it?

Nowadays the term “Gamification” has officially joined our vocabulary, but what is...
Read More

Leave a Reply

Your email address will not be published. Required fields are marked *