Pull to refresh

Unity 2D: работа со спрайтами в разных разрешениях дисплея

Development of mobile applications *Game development *Unity3D *
Sandbox

Начиная с версии 4.3 в Unity появилась возможность работы с 2D графикой, большая часть новых стандартных решений мне пришлись по душе, потому что я как раз незадолго до этого обновления перешел с Corona SDK.
Но что меня не порадовало, так это отсутствие стандартных инструментов для оптимизации спрайтов под разные разрешения экранов, что имеет довольно таки существенное влияние на производительность на маломощных устройствах.

Конечно, можно использовать что-то похожее на 2D Toolkit для решения этой проблемы, но зачем платить 75$ если можно сделать все самому?

Cо слов пользователей официального форума Unity, разработчики в скором времени не планируют расширять 2D функционал, по крайней мере до релиза 5 версии Unity, и пока что пользователи должны самостоятельно решать данную проблему. Бороздя просторы интернета в надежде найти ответ, я набрел на интересный доклад одного из разработчиков Unity на летней Nordic Game Conference 2014, название говорит само за себя «2D issues and how to solve them». Пользуясь материалами этого доклада, я сделал свое решение проблемы поддержки дисплеев разного разрешения.

Для того чтобы начать, нам нужна только версия атласа спрайтов с самым высоким разрешением, остальные манипуляции с уменьшением качества атласов происходят внутри Unity.

Подготовка спрайтов

Итак, на первом этапе мы должны организовать атласы спрайтов для разных разрешений: SD, HD, ultra-HD, у нас же будут использованы суффиксы 1x, 2x, 4x.

Берем атлас спрайтов, в нашем случае это ’spritesheet1@4x.png', в инспекторе выбираем нужные параметры, режем атлас в Sprite Editor, если требуется. Создаем еще две копии атласа в Project Browser (cmd+D, ctrl+D) и переименуем их так, чтобы суффиксы в названии были '@2x', '@1x’, меняем свойство Max Size на значение в 2 и в 4 раза меньше соответственно.

Спрайты должны находится в папке Resources, если таковой не имеется — создайте. Это позволяет загружать файлы с этой папки во время выполнения программы.





Обращу Ваше внимание на поля Pixels Per Unit и Format, первое поможет подобрать размер спрайтов под размеры сцены без изменения scale, а второе является очень важным для правильной передачи цвета, размера билда и использования ресурсов графического процессора. На эту тему есть замечательный мануал

Подготовка префаба

Тут все просто, мы собираем игровой объект на основе атласа спрайтов с суффиксом ‘@2x’, добавляем анимацию и любые другие фишки, которые могут вам понадобится. Сохраняем объект как префаб.
Суффикс ‘@2x’ был выбран, потому что большая часть устройств имеют hd разрешение, нам не придется делать лишнюю работу в большинстве случаев.

Скрипт

Скрипт будет работать с любым количеством компонентов SpriteRenderer. Он не будет влиять ни на анимацию, ни на что другое, главное чтобы имена спрайтов в атласе и SpriteRenderer`е были одинаковыми. Данную особенность можно применять не только для смены разрешения спрайтов, но и для замены их на полностью другие, например при создании другого скина персонажа.

Основной принцип работы скрипта таков: у нас есть публичная переменная spriteSheet, в которой мы передаем имя атласа, в котором находятся спрайты нашего объекта.



С помощью метода GetQuality узнаем с каким дисплеем мы имеем дело (для моих целей было достаточно ориентироваться на высоту экрана).

Потом в методе ManageQuality, имея данные о разрешении экрана, загружаем в массив sprites все спрайты нужного нам атласа с правильным суффиксом. В массив renderers загружаем все компоненты SpriteRenderer, которые находятся в объекте. Ищем в массиве sprites спрайт по имени и присваиваем его спрайту компонента SpriteRenderer, если такой существует. Завершает все Resources.UnloadUnusedAssets (), этот метод выгружает из памяти неиспользуемые ассеты.

Тут находится скрипт
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<Sprite>(spriteSheet + "@" + qSuffix);

			if (sprites != null) {
				SpriteRenderer[] renderers = GetComponentsInChildren<SpriteRenderer>(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 ();

	}

}


Также этот скрипт можно использовать для изменения всех спрайтов в сцене. Для этого создаем новый объект, например SpriteManager, и добавляем к нему данный скрипт, но с измененным определением массива renderers:

SpriteRenderer[] renderers = GameObject.FindObjectsOfType<SpriteRenderer>();

Спасибо за внимание, надеюсь статья была вам полезна.
Tags:
Hubs:
Total votes 18: ↑16 and ↓2 +14
Views 46K
Comments Comments 10