- PVSM.RU - https://www.pvsm.ru -

Unity3d, в помощь начинающим

Unity3d, в помощь начинающим
Эта статья предназначена для тех пользователей unity3d, что уже хорошо знакомы с самим движком, но ещё не обладают достаточной собственной базой знаний для того, чтобы писать без дополнительного сёрфинга по интернету, с целью поиска возникающих иногда фундаментальных вопросов. Чтобы сократить некоторым время на ресёч, расскажу несколько важных фишек, которые необходимо знать каждому unity программисту. Если у Вас возникают вопросы: как сделать чтобы у Вас не тормозило на чём-то послабее iPad 3, или Вы не знаете как удобно работать со спрайтами, как заставить музыку не прерываться при загрузке, или как обойти максимальный допустимый размер под android (50 мегабайт) и так далее, возможно Вы найдёте ответ в этой статье.

Статья затрагивает лишь проблемы мобильной разработки (IOS, Android). Все примеры только на C#.

Автор статьи не претендует на абсолютную категоричность и правильность предложенных решений.

Основы основ

1) Обязательно почитайте рекомендации [1]от разработчиков Unity, как писать оптимальные с точки зрения производительности скрипты.

2) Лучше всего создать класс, прямой наследник от MonoBehaviour, который реализует кеширование transform и остальных подобных свойств MonoBehavior, все основные скрипты наследовать от него:

Код с примером кэширования

public class Qwant : MonoBehaviour {
    private Transform _qwantTransform = null;
    public Transform qwantTransform {
        get {
            if (_qwantTransform == null) {
                _qwantTransform = transform;
            }
            return _qwantTransform;
        }
        protected set {
            _qwantTransform = value;
        }
    }
}

3) Используйте для хранения глобальных параметров своей игры статический класс со статическими методами и полями (если конечно данные не должны быть сохранены при закрытии игры, тогда пользуйте PlayerPrefs) но такой объект должен быть всего один, не увлекайтесь. Храните в нем только такие глобальные вещи, как текущее состояние игры (игра на паузе; мы в меню; cписок доступных пёрхейзов с их ценами, полученный с сервера и т.п.)

4) Всегда используйте (даже если ваша игра вся в 2D) две камеры одну для игровых объектов, другую для GUI, указывайте у GUI-элементов необходимый слой (слой GUI камеры и будет Вам счастье) Конечно это не касается случаев меню, где и одной камеры предостаточно.

Скриншот с GUI камерой

Unity3d, в помощь начинающим

5) Если Вы хотите, чтобы ваш GUI под iPad выглядел не размытым а так же на всех устройствах одинаковым, Вы не хотите его ресайзить в зависимости от размеров экрана, сделайте для GUI камеры size — 1,59. Спокойно верстайте всё под размер iPad2, на других устройствах всё будет отмасштабировано само.

6) Если необходимо перетащить несколько объектов в список другого объекта, и не хочется перетаскивать их по одному, можно зафиксировать объект, отображаемый в инспекторе, нажав на замочек в правом верхнем углу (на предыдущей картинке его тоже можно заметить).

Работа с 2d спрайтами (плагин tk2d)

В Unity3d для работы с 2d спрайтами нет практически никаких инструментов. Создать текстурную карту без использования плагинов Вы не сможете, да и писать спрайтовую анимацию Вам придется самостоятельно (в 4 unity это дело немного поправили). Для работы со спрайтами лучше всего использовать плагин tk2d [2]. Плагин на момент написания статьи стоил 65$, и, на мой взгляд, отрабатывает их на все 100%. Плагин позволяет:

 Создавать текстурные карты различного размера (при этом позволяет разрезать исходные текстуры так, что они влезут);
 создавать спрайтовые анимации;
 работать с текстурным шрифтом;
 tk2dCamera? (Не разу не пользовался, но разработчики плагина рекомендуют, наверно действительно стоящая вещь!);
 снабжён достаточно толковой документацией и туториалами.

За достаточно долгое и плотное использование плагина не было замечено ни одного бага.

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

Пример: PlaneResizer.cs [3]

Графический текст

Какая же игра без красивого шрифта? Для создания красивого графического текста лучше всего использовать Glyph Designer [4], работает только под Mac, платная, но зато удобная. Имеется как минимум два бесплатных аналога, работающие под Windows, но по-настоящему красивый текст в них Вы не получите.

Программы по созданию графических шрифтов создадут xml и текстурную карту, используйте их в tk2d или в бесплатном EZ GUI.

Pool объектов

Одна из проблем, с которой можно столкнуться при написании игры – это большая дороговизна операции создания объекта, т. е. дороговизна операции Instantiate. Для решения этой проблемы для начала можно воспользоваться CoRoutine’ом, но если на мобильном устройстве тормозит даже создание одного объекта, тогда необходимо использовать порождающий паттерн проектирования Объектный пулл [5].

Таким образом можно избавиться от лагов при создании объектов, и все их можно инстанциировать при загрузке уровня. Нужный объект очень удобно искать и получать по полю name.

Это единственный способ борьбы с лагами при написании игры с динамически генерируемым уровнем, например, при написании раннера.

Quality Levels

Мобильные устройства – очень разные по разрешению, но всегда хочется добиться, чтобы игра работала с хорошей производительностью на всех устройствах. Готовить несколько различных билдов для различных устройств (4 apk для android и 2 билда для iOS) абсолютно необязательно.

Сначала правильно настройте Quality уровни в игре (Edit->Project settings->Quality):

Скриншот с настройками Quality

Unity3d, в помощь начинающим

В unity3d есть замечательная возможность переключать Quality прямо на этапе запуска приложения.

Таким образом: необходимо создать нужные нам Quality Levels, и написать небольшой скрипт, который можно повесить на пред загрузочную сцену. Этот скрипт будет переключать качество, в соответствии с любыми нашими условиями.

Например, можно менять качество текстур от Full Res до Quarter Res. Из всех функций и свойств нам могут понадобиться, только:

 QualitySettings.names;
 QualitySettings.SetQualityLevel (int).

Пример такого скрипта: CorrectQuality.cs [6]

DontDestroyOnLoad объекты и бесконечная музыка

Если необходимо, чтобы главная тема приложения проигрывалась беспрерывно, даже при перезагрузке из одной сцену в другую необходимо использовать DontDestroyOnLoad (gameObject);

Т. е. объект с нашей музыкой не удаляется никогда. Важно учесть, чтобы таких наших неудаляемых объектов не получилось в результате несколько. Для этого целесообразно использовать паттерн программирования Singleton [7].

Таким же образом организуются и другие не удаляемые объекты.

Пример такого скрипта: Music.cs [8]

TouchDispatcher

События touch – есть разделяемый ресурс. Для удобного использования необходимо написать некий контроллер, который будет раздавать получаемые события между обрабатывающими их объектами.

На мой личный взгляд очень удобно это организованно в cocos2d/x [9], за основу и была взята предложенная этим игровым движком концепция:

1) есть интерфейс, содержащий обработку 4 стандартных функций touch событий: TouchBegan, TouchMoved, TouchCancelled, TouchEnd. Если объект отлавливает touch события, он реализует этот интерфейс.
2) Есть класс TouchDispatcher – класс, управляющий и делегирующий события.

Для удобства тестирования необходимо, чтобы не было разницы между мышкой и пальцем, всё-таки компилировать под устройство – долго. Также надо учесть следующее:

a) возможность использования multitouch
b) захватывает(swallow) объект touch событие или нет
c) приоритет объектов
d) добавление объекта в список делегатов
e) удаление объекта из списка делегатов

После написания такого простенького класса, работа с touch становится очень удобной, простой и ясной. Полученный скрипт вешается на GameObject, который помещается в корень сцены, например под именем SharedTouchDispatcher. Скрипт реализующий интерфейс делегата, ищет наш TouchDispatcher посредством GameObject.Find(“/SharedTouchDispatcher”).

Пример: TouchDispatcher.cs [10], TouchTargetedDelegate.cs [11]

AccelerometerDispatcher

Всё что, написано выше для TouchDispather’а справедливо и для аккселерометра, с одним лишь исключением: аккселерометр у устройсва всегда только один, а значит, и код реализующего контроллера немного проще.

Есть только одна особенность, про которую нельзя забывать, при работе с акселерометром: если устройство перевёрнуто вверх ногами: PortraitUpsideDown или LandscapeRight, нельзя забывать, что меняются значения по оси x или y, соответственно. Мы получим обратно-ориентированное управление, не учтя это.

Пример: AccelerometerDispatcher.cs [12], AccelerometerTargetedDelegate.cs [13]

Проверка попадания точки в concave полигон

Одна из самых распространённых задач компьютерной графики. Если коротко: точка находится внутри невыпуклого полигона, если луч, направленный в любую сторону пересекает края полигона нечётное количество раз.

Сам алгоритм можно легко найти в интернете.

Я рассматриваю эту задачу сейчас в контексте попадания touch в объект GUI (Конечно, можно всё делать проверкой попадания луча в collider, но, на мой взгляд, для 2D объектов лучше использовать предложенный ниже способ).
Для простых кнопок можно использовать обычные прямоугольники и touchZone.Contains(position);. Но если объекты – сложной формы, и перекрывают друг друга – этого будет недостаточно.

Координаты обводки – полигона нашей условной кнопки можно взять из VertexHelper [14], к сожалению, не знаю ничего лучше и ничего для windows.

В результате мы получим координаты относительно центра нашего 2D объекта, что нам и нужно.

Полученную строку легко загнать в наш обрабатывающий скрипт, и распарсить на массив точек:

Код с примером распарсивания строки в массив точек

private void ParsePath(){
	//получили массив пути
	char []separator={',','n'};
	string []numbers=pathTouch.Split(separator);
	Path= new Vector2[numbers.Length/2];
	for (int i=0;i+1<numbers.Length;i+=2){
		Path[i/2]=new Vector2(float.Parse(numbers[i],NumberStyles.Currency),float.Parse(numbers[i+1],NumberStyles.Currency));
	}
}

Таким образом, осталось только реализовать алгоритм поиска пересечения прямых.

Пример реализации: Crossing.cs [15]

Также прилагается макет класса, реализующий интерфейс делегата touch событий, и проверяющий попадания пальца в обводку.

Пример: SpriteTouch.cs [16]

Догрузка уровней из интернета WWW

Если у Вас возникла необходимость догрузить часть уровней из интернета после установки игры, то WWW.LoadFromCacheOrDownload [17] – Ваш лучший друг. Но он работает только в Unity Pro.

Загружать можно только специально подготовленные сцены, создавать такие можно при помощи
BuildPipeline.BuildStreamedSceneAssetBundle [18]. Честно говоря под Unity 3.5.2 довольно глючно работало под IOS, но я думаю с тех времён это дело поправили.

В документации Unity подробно и исчерпывающе описан весь процесс организации загрузки уровней из сети.

Заключение

Надеюсь кому-то предложенная статья будет полезной, и поможет сэкономить немного времени.

Почти всё из описанного выше, было использовано здесь [19]:

Автор: Alexey_Bespaly

Источник [20]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/ios/25909

Ссылки в тексте:

[1] рекомендации : http://docs.unity3d.com/Documentation/ScriptReference/index.Performance_Optimization.html

[2] tk2d: http://www.unikronsoftware.com/2dtoolkit/

[3] PlaneResizer.cs: https://docs.google.com/file/d/0B3qT68vqKgeaNHoyWFRNQmhxQkU/edit

[4] Glyph Designer: http://www.71squared.com/en/glyphdesigner

[5] Объектный пулл: http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D1%8B%D0%B9_%D0%BF%D1%83%D0%BB

[6] CorrectQuality.cs: https://docs.google.com/file/d/0B3qT68vqKgeaNWVzMmVIcVhJaXM/edit

[7] Singleton: http://en.wikipedia.org/wiki/Singleton_pattern

[8] Music.cs: https://docs.google.com/file/d/0B3qT68vqKgeaWEhQWFVsbDAtdDA/edit

[9] cocos2d/x: http://cocos2d-x.org/

[10] TouchDispatcher.cs: https://docs.google.com/file/d/0B3qT68vqKgeadmFmeGNtbFJvQlU/edit

[11] TouchTargetedDelegate.cs: https://docs.google.com/file/d/0B3qT68vqKgeaMW9SVlMxYmJveTg/edit

[12] AccelerometerDispatcher.cs: https://docs.google.com/file/d/0B3qT68vqKgeacDd2ZnFHNVhWZ3c/edit

[13] AccelerometerTargetedDelegate.cs: https://docs.google.com/file/d/0B3qT68vqKgeadHRjZ3JSSHh4Sk0/edit

[14] VertexHelper: https://github.com/jfahrenkrug/VertexHelper

[15] Crossing.cs: https://docs.google.com/file/d/0B3qT68vqKgeaNGxWT2ZmLTVkOW8/edit

[16] SpriteTouch.cs: https://docs.google.com/file/d/0B3qT68vqKgeadjVfM1ZxUUxpLVE/edit

[17] WWW.LoadFromCacheOrDownload: http://docs.unity3d.com/Documentation/ScriptReference/WWW.LoadFromCacheOrDownload.html

[18] BuildPipeline.BuildStreamedSceneAssetBundle: http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.BuildStreamedSceneAssetBundle.html?from=WWW

[19] здесь: http://squeakyoak.com/ru/ru-games/particle-rus

[20] Источник: http://habrahabr.ru/post/167541/