Unity 2D: working with sprites in different display resolutions


Starting with version 4.3, Unity has the opportunity to work with 2D graphics, I liked most of the new standard solutions because I just switched from the Corona SDK shortly before this update.
But what did not please me was the lack of standard tools for optimizing sprites for different screen resolutions, which has a pretty significant impact on performance on low-power devices.

Of course, you can use something similar to the 2D Toolkit to solve this problem, but why pay $ 75 if you can do everything yourself?

According to the words of users of the official Unity forum, developers are not planning to expand 2D functionality soon, at least until the release of version 5 of Unity, and for now, users must solve this problem on their own. Surfing the Internet in the hope of finding an answer, I came across an interesting report by one of the Unity developers at the summer Nordic Game Conference 2014, the name speaks for itself “2D issues and how to solve them” . Using the materials from this report, I made my solution to the problem of supporting displays of different resolutions.

In order to start, we only need the highest resolution version of the atlas of sprites, the rest of the manipulations with reducing the quality of atlases occur inside Unity.

Sprite preparation

So, at the first stage, we need to organize sprite atlases for different resolutions: SD, HD, ultra-HD, but we will use the suffixes 1x, 2x, 4x.

We take the sprite atlas, in our case it is 'spritesheet1@4x.png', in the inspector we select the necessary parameters, we cut the atlas in the Sprite Editor, if necessary. Create two more copies of the atlas in Project Browser (cmd + D, ctrl + D) and rename them so that the suffixes in the name are '@ 2x', '@ 1x', change the Max Size property to a value of 2 and 4 times less respectively.

Sprites should be located in the Resources folder, if there is none, create it. This allows you to download files from this folder during program execution.





I’ll draw your attention to the Pixels Per Unit and Format fields, the first will help you choose the size of the sprites to fit the scene without changing the scale, and the second is very important for the correct color, build size and use of GPU resources. There is a wonderful manual on this topic

Preparing a Prefab

Everything is simple, we collect a game object based on a sprite atlas with the suffix '@ 2x', add animation and any other chips that you may need. Save the object as a prefab.
The suffix '@ 2x' was chosen because most of the devices have hd resolution, we do not have to do too much work in most cases.

Script

The script will work with any number of SpriteRenderer components. It will not affect either the animation or anything else, the main thing is that the names of the sprites in the atlas and SpriteRenderer are the same. This feature can be used not only to change the resolution of sprites, but also to replace them with completely different ones, for example, when creating another character skin.

The basic principle of the script is as follows: we have a public variable spriteSheet, in which we pass the name of the atlas in which the sprites of our object are located.



Using the GetQuality method, we find out which display we are dealing with (for my purposes, it was enough to focus on the height of the screen).

Then, in the ManageQuality method, having data on the screen resolution, we load into the sprites array all the sprites of the atlas with the correct suffix. In the renderers array, load all the SpriteRenderer components that are in the object. We look for a sprite by name in the sprites array and assign it to the sprite of the SpriteRenderer component, if one exists. Completes all Resources.UnloadUnusedAssets (), this method unloads unused assets from memory.

Here is the script
using UnityEngine;
using System.Collections;
using System;
public class ConstObjectsQuality : MonoBehaviour {
	public string spriteSheet;
	private string qSuffix;
	void Awake(){
		qSuffix = GetQuality ();
		ManageQuality ();
	}
	private string GetQuality(){
		int screenH = Screen.height;
		print (screenH);
		if (screenH > 1440)
			return "4x";
		else if (screenH < 720)
			return "1x";
		else
			return "2x";
	}
	private void ManageQuality(){
		if (qSuffix == "1x" || qSuffix ==  "4x") {
			Sprite[] sprites = Resources.LoadAll(spriteSheet + "@" + qSuffix);
			if (sprites != null) {
				SpriteRenderer[] renderers = GetComponentsInChildren(true);
				if (renderers.Length > 0) {
					foreach (SpriteRenderer r in renderers)
					{
						if (r.name != null){
							string spriteName = r.sprite.name;
							Sprite newSprite = Array.Find(sprites, item => item.name == spriteName);
							if (newSprite)
								r.sprite = newSprite;
						}
					}
				}
			}
		}
		Resources.UnloadUnusedAssets ();
	}
}


Also, this script can be used to change all the sprites in the scene. To do this, create a new object, for example, SpriteManager, and add this script to it, but with the changed definition of the renderers array:

SpriteRenderer[] renderers = GameObject.FindObjectsOfType();

Thank you for your attention, I hope the article was useful to you.

Also popular now: