Buffer icon Проекты
79 заметок с тегом

разработка

Позднее Ctrl + ↑

Рисование кривых в Unity

Как нарисовать линию в Unity? А как кривую Безье? Очень просто! В Unity уже есть достаточно продвинутый компонент LineRenderer, его то я и использовал в одном из своих проектов. После упаковки в один скрипт, я бы даже сказал — в одну функцию, получилось вот что:

Можно настраивать количество сегментов в линии (качество), начальный и конечный цвет, и конечно ширину.

Исходник на Github

 Нет комментариев    1331   2016   unity   графика   разработка

Выполнение в главном потоке Unity

Обновлено 18.09.2017
Лучше использовать Dispatcher из UnityToolbag.

Как в Unity быстро запустить процедуру в основном потоке? Для таких вещей, у меня есть маленький скрипт Tasker.

using UnityEngine;
using System.Collections.Generic;

public delegate void Task ();

public class Tasker : MonoBehaviour {

	private static Tasker _instance;								
	private Queue<Task> _taskQueue = new Queue<Task> ();
	private object _queueLock = new object ();

	void Awake () {
		_instance = GetComponent<Tasker>();
	}
		
	void FixedUpdate () {
		lock (_queueLock) {
			if (_taskQueue.Count > 0)
				_taskQueue.Dequeue ()();
		}
	}

	public static void Run (Task newTask) {
		lock (_instance._queueLock) {
			if (_instance._taskQueue.Count < 100)
				_instance._taskQueue.Enqueue (newTask);
		}
	}
}

Чтобы запустить что-то в главном потоке, нужно вызвать функцию Run:

Tasker.Run (new Task (delegate {
// выполнение в главном потоке
}));
 Нет комментариев    359   2016   unity   разработка

Бесконечный скроллинг в Unity

Обновлено 07.09.2018
Теперь можно использовать ячейки разной высоты!
Добавил новые демки

Когда делаешь игру под мобильную платформу, пусть Android или iOS, иногда хочется использовать стандартные для этой платформы компоненты, потому что они проверены, оптимизированы и быстро работают. Например, списки. Кто делал в Unity интерфейс с большим количеством прокручивающихся элементов в Scrollrect, наверняка замечали, что после определенного количества, вся эта конструкция начинает притормаживать. Наиболее оптимально использовать т. н. data driving подход, когда количество видимых элементов не меняется, а данные подгружаются динамически в нужную ячейку.

Для одного проекта понадобилось сделать списки друзей и лидеров. Количество пользователей сотни тысяч. Естественно, создавать такое количество ячеек было бы неверно. Быстрый поиск показал несколько рабочих вариантов, но после тестов на реальных устройствах, при быстрых прокрутках лаги все равно были заметны и еще по ряду причин не подошли. Последний найденый вариант лег в основу и после доработок, отлично функционирует.

Была сделана такая знакомая мобильным разработчикам функция, как pull-to-refresh, также, ячейки можно настраивать как угодно под ваш проект, нужное количество создается автоматически в зависимости от высоты экрана. Единственное ограничение — высота ячейки не динамическая.

Использовать очень легко — все делает один скрипт, вещаем его на Scrollview настраиваем параметры и коллбеки и все. Демо есть. Если будут какие-то вопросы и пожелания, не стесняйтесь писать. Удачи!

Ссылка на Github

 Нет комментариев    3184   2016   unity   интерфейс   разработка

Структура Unity проекта

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

Можно гуглить «best practices» и смотреть как делают другие, но все равно вы придёте к своему комфортному расположению ресурсов и элементов на сцене. А для тех, кто еще не определился с выбором, предлагаю свой вариант.

И так, структура папок:

  • Editor
  • Audio
    • Music
    • Effects
  • Models
  • Plugins
    • iOS
    • Android
  • Prefabs
  • Resources
    • Prefabs
    • Sprites
    • Etc
  • Textures
  • Animations
  • Scenes
    • Levels
    • Menu
    • Etc
  • Scripts
  • Shaders
  • Vendor

Естественно, все нужно подстраивать под конкретную задачу и под команду, но будет лучше если придерживаться общей концепции для всех своих проектов.

Структура сцены:

  • Plugins
  • Scripts
  • Level
  • UI
  • Render
    • Cameras
    • Lights
    • Effects
  • !Temporary

Scripts служит для скриптов которые не связаны с объектами, например, менеджер звуков. Plugins нужен если обрабатываете входящие сообщения из плагинов iOS и Android. В !Temporary добавляются динамические, временные элементы созданные в процессе игры. Если вы делаете 2D игру, то в Level разумно было бы добавить разбивку по «слоям»: background, middleground, foreground.

Пробуйте, создавайте! Все придет с опытом. В любом случае, такой шаблон удобнее и практичнее, чем куча файлов в корневой папке и раскиданные элементы по сцене :)

 1 комментарий    1770   2016   unity   разработка

Загрузка файлов с сервера в Unity

Простой пример, как загружать файлы в игру со своего сервера. Например, для уменьшения установочной файла — тяжелые текстуры и звуки загружаем при первом запуске игры или в фоне. Вешаем скрипт на объект и пользуемся.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class HTTP : MonoBehaviour {

	public delegate void HTTPResponse (int code, WWW www);		
	public const int OK = 100;														
	public const int ERROR = 101;													
	private static HTTP _http;					

	public static HTTP instance {
		get {
			if (!_http) {
				_http = FindObjectOfType (typeof (HTTP)) as HTTP;
				if (!_http) 
					Debug.LogError ("There needs to be one active HTTP script on a GameObject in your scene.");
			}
			return _http;
		}
	}

	public static void GET (string url, HTTPResponse callback) {
		instance.StartCoroutine (instance.WaitForRequest (new WWW (url), callback));
	}

	public static void POST (string url, Dictionary<string, string> postData, HTTPResponse callBack) {
		WWWForm form = new WWWForm();
		foreach (KeyValuePair<String, String> param in postData)
			form.AddField(param.Key, param.Value);
		instance.StartCoroutine (instance.WaitForRequest (new WWW (url, form), callBack));
	}

	IEnumerator WaitForRequest (WWW www, HTTPResponse callback) {
		yield return www;
		if (www.error == null)
			callback (OK, www);
		else 
			callback (ERROR, www);
	}
}

Можно запускать хоть несколько потоков. Использовать очень просто:

HTTP.GET ("http://yandex.ru", (int code, WWW www) => {
	if (code == HTTP.OK) {
		string html = Encoding.UTF8.GetString (www.bytes, 0, www.bytes.Length);
		Debug.Log (html);
	} 
});

Только не забывайте освобождать объект WWW в коллбеке :) www.Dispose();

 Нет комментариев    1381   2016   unity   разработка

Настройка Sublime Text для Unity

Эта заметка больше для разработчиков использующих OS X (Mac OS уже). Потому как, разница между Visual Studio и MonoDevelop, просто разительна, как и скорость работы.

Но есть отличное решение — Sublime Text (ST). Установив несколько плагинов, и без того быстрый и многофункциональный ST, прекрасно подойдет для разработки на C# в Unity. После настройки, вы получите:

  • Автодополнение кода — autocompletion
  • Переход к функции — go to definition
  • Подсветка ошибок и синтаксиса
  • Сворачивание фрагментов кода — code folding
  • XML документирование

Установка Mono

Сначала нужно поставить Mono — open-source реализация .NET фреймворка, он нужен для компиляции и запуска C# скриптов на маке. Его можно установить, например, с помощью Brew:

brew install mono

Установка Package Control для Sublime

Если в вашем ST еще не установлен пакетный менеджер, то сделать это очень просто: нужно открыть консоль внутри ST, вставить кусок кода и нажать Enter.

Установка Omnisharp

Основной плагин который позволит ST работать с C#. Для установки: открывает пакетный менеджер (cmd+shift+p → Install Package), ищем Omnisharp и устанавливаем.

Настройка проекта

Теперь надо создать Sublime Project и связать его с Unity проектом. Для этого: открываем в ST корневую папку с проектом и идем в меню Project → Save Project As.... Сохраняем файл проекта рядом с *.sln файлом для удобства.

Открываем только что созданный файл MyProject.sublime-project в текстовом редакторе, можно в том же ST и редактируем его:

{
    "folders":
    [
        {
            "path": ".",
            "file_exclude_patterns": ["*.meta"],
        },
    ],
    "solution_file": "./MyProject.sln"
}

Тут немного объясню:

  • path — путь до папки со скриптами, в данном случае корневая папка, но вы можете написать например Scripts, или ту где у вас лежат скрипты
  • file_exclude_patterns — файлы с какими расширениями не показывать в проекте
  • solution_file — самое главное, тут должно быть название вашего SLN файла проекта

Устанавливаем плагины

Для документирования устанавливаем плагин — XmlDocs, для сворачивания кода — SyntaxFold. Устанавливаем также, через пакетный менеджер. Чтобы задокументировать код: вводим три слеша и жмем табуляцию — (/// + tab). А для настройки сворачивания кода, после установки плагина, нажмите shit+f5 и выберите C#.

Последние штрихи

Чтобы автодополнение кода работало не только по ctrl+space, а каждый раз когда вы ставите точку, в конфиг надо добавить правки. Убедитесь, что у вас открыт C# файл, и выбран синтаксис C# (в правом нижнем углу), далее идем в меню: Sublime Text → Preferences → Settings — More → Syntax Specific — User и вставляем этот код:

{
    "auto_complete": true,
    "auto_complete_selector": "source - comment",
    "auto_complete_triggers": [ {"selector": "source.cs", "characters": ".<"} ],
 }

Если вдруг автодополнение кода не заработало, перезагрузить ваш SLN файл: жмем cmd+shift+p, и выбираем OmniSharpSublime: Reload Solution.

Еще момент: это настройка ST для редактирования уже имеющего проекта. И мы не делаем его редактором по-умолчанию. Т. е. если вы откроете файл двойным кликом из Unity, то Omnisharp сервер не запустится. Для «корректного» открытия проекта, нужно в ST выбрать меню: Project → Open Project... и выбрать MyProject.sublime-project файл.

Готово

Теперь можно быстро и комфортно писать C# код для Unity на маке. Конечно, можно поставить еще плагинов, тут уже на ваше усмотрение. Например, есть плагин со сниппетами для C#, ищется в пакетном менеджере по словам C# Snippets.

Только для любителей Sublime Text :) Удачи!

 3 комментария    6801   2016   unity   разработка

Оптимизация 2D игр на Unity

Этот пост будет периодически дополняться и обновляться.
Обновлено 13.10.2021

На Youtube куча уроков по созданию простейших 2D игр на Unity. Реально, сделать неплохой платформер можно за день, при наличии опыта и готовых ассетов. Но многие начинающие игроделы сделав проект и протестировать его на ПК, с ужасом наблюдают как их творение тормозит на мобильном устройстве.

В мануалах, что встречаются в сети, большинство советов собрано к версии Unity 4.6+, кроме того, они почти все на английском, что для некоторых является преградой. В этом посте, я постарался собрать те моменты, которые помогли мне избавится от лагов на iOS и Android. Но важно понимать — не все можно решить лишь настройками, очень важна и архитектура приложения, и подготовленные текстуры, и знание более оптимальных алгоритмов.

Что нужно предпринять, чтобы повысить производительность, поднять FPS, снизить CPU?

1. Кешируем все!

Все, что будет использоваться больше одного раза лучше закешировать. Операции типа GameObject.Find() или GetComponent() достаточно ресурсозатратны, а если они вызываются где-нибудь в цикле или в Update (), то производительность может упасть.

void Awake () {
	_cachedTransform = transform;
}
 
void Update () { 
	_cachedTransform.localPosition = _newPosition;		
}

Не используйте Resources.Load () каждый раз когда нужно в рантайме загрузить что либо, это тоже дорогая операция. Лучше при старте закешировать и работать с кешем. Ну и конечно, объединяйте в префабы.

2. Настройки графики

В Unity есть 6 стандартных пресетов настройки качества графики. Но так как мы говорим про оптимизацию для 2D и для мобильных устройств, то все что выше Simple нет смысла ставить. Конечно, если у вас есть какие-то специфические моменты, частицы, и т. д., то с параметры можно поэкспериментировать найдя оптимальный баланс.

3. Используем FrameRate

По-умолчанию FrameRate равен 30. И зачастую этого бывает достаточно. Но например, при создании UI где есть прокручивающие списки и движущие элементы, может появится дрожание или шлейф. Я это заметил при тестировании на iPhone, поэтому вручную повысил FrameRate. А понижая FrameRate на сценах или игровых меню, где ничего не двигается, можно значительно снизить CPU, а следовательно продлить жизнь батарее устройства. Пользователи не любят когда игра сжирает аккумулятор за час.

public int _frameRate = 60;

void Start () {
	#if UNITY_IOS
		QualitySettings.vSyncCount = 0;
	#endif
}

void Update () {
	#if UNITY_IOS
		if (_frameRate != Application.targetFrameRate)
			Application.targetFrameRate = _frameRate;
	#endif
}

4. Атлас текстур

Определенно, нужно упаковывать все свои спрайты в атласы. Для этого есть как встроенный инструмент Sprite Packer, так и продвинутый TexturePacker. Для работы встроенного упаковщика, достаточно задавать теги в настройках импорта, объединяя текстуры и спрайты по смыслу и месту использования.

Таким образом уменьшается количество вызовов отрисовок ваших спрайтов. Проверить как идет отрисовка можно с помощью встроенного инструмента Frame Debugger.

5. Используем пул объектов

GameObject.Instantiate () — очень дорогая операция! Если есть возможность не использовать ее в процессе игры — не используйте. Для большого количества однотипных объектов надо использовать пул объектов. Один раз инициализировав определенное количество, например пуль, они будут использоваться снова и снова, вместо создания и уничтожения каждый раз. Урок по пулу объектов и готовый шаблон, для начала будет достаточно.

6. Меньше Update — больше событий

Метод Update () вызывается каждый кадр, FixedUpdate () в некоторых случаях еще чаще. Если у вас в этих местах происходит много различных проверок и действий, это можно сказаться на производительности. Я использую событийную модель: вместо проверки условия в Update (), когда происходит какое-либо действие, отправляется событие, а в нужном месте это событие «слушается» и обрабатывается в зависимости от переданных параметров. Для этого можно использовать менеджер событий о котором я писал ранее.

7. Выключаем неиспользуемые компоненты

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

8. Настройки билда

Билд под конкретную платформу, тоже можно оптимизировать. Например, если акселерометр не используется в игре, его лучше вообще отключить. Кроме того, я не использую автовыбор графического API, а задаю его сам убирая все остальные, опять же, если вы не используете какие-то специфические функции из OpenGLES 3.0, а так второй версии вполне хватает, она уже давно протестирована. Включаем статичный и динамический батчинг, а для Android многопоточный рендеринг. Для iOS включаем Script Call Optimization в Fast but no Exceptions, но тут момент — если будет какое-то исключение, то игра крашится.

9. Используем Profiler

Не стоит обделять вниманием профайлер. Обязательно протестируйте свою игру и посмотрите, в какие моменты идет максимальная нагрузка. Эти места нужно оптимизировать в первую очередь. Большинство ответов можно найти на stackoverflow.com или форуме Unity, просто загуглив название метода который тратит больше всего ресурсов.

10. Использование материала для UI Image и SpriteRenderer

Если у вас сложный интерфейс и много компонентов, особенно UI Image, то они существенно будут влиять на FPS. Чтобы повысить производительность, улучшить плавность анимаций, можно применить такой хак: там где вы не используете маски, у картинок нужно задать материал Sprites-Default. Если это сделать вместе с маской, то маска не сработает и получите примерно такой варнинг:

Material Sprites-Default doesn’t have _Stencil property

Чтобы убрать эту ошибку нужно немного изменить стандартный шейдер, сделать новый материал и применить его там где есть маска, тогда все сработает. Ссылка на измененный шейдер.
Цена плавности — повышение CPU :(

11. Уменьшаем размер текстур

Отличная утилита которая позволяет снизить потребления памяти для текстур до 3х раз. Как это работает и ссылка на Github, в статье на Хабре.

12. Практическое руководство по оптимизации Unity игр

Подойдет как для 2D, так и для 3D. Много полезной информации которую в документации вряд ли найдешь. Тут и про инструменты, и про опыт. Рассказывает специалист по эксплуатации из Unity Technologies — очень интересно. Узнал про memory profiler и то, что Camera.main не закеширована О_О. Обязательно смотреть всем.

13. Используем оптимизированный код

Снова хочется посоветовать набор оптимизированных скриптов от Leopotam. Коллекции, сериализация, векторы и многое другое. Настоятельное рекомендую, к изучению и использованию.

14. Используем одинаковые материалы

Если на объектах стоят разные материалы, они не будут батчится и будет больше вызовов отрисовки. Соответственно, нужно по возможности использовать как можно меньше разных шейдеров и материалов. Для понимания, как работает начальная оптимизация графики 2D, на Lynda.com есть небольшой курс.

15. Размеры атласов и спрайтов

Для применения сжатия спрайтов на мобильных устройствах нужно использовать атласы с размерами кратными степени 2, т. е. 1024х1024, 2048х2048.

16. Используйте UI Profiler

В Unity 2017 появился UI Profiler! Крутая штука, теперь можно выяснить почему в интерфейсе много вызовов отрисовки, увидеть какие материалы на объектах и всё это оптимизировать. Особенно актуально, если у вас сложные интерфейсы со множеством элементов, которые например, прокручиваются в ScrollRect.

17. Уголок оптимизатора

На сайте Unity появился специальный раздел посвященный оптимизации — Optimization corner. Там и про UI, и профайлеры, и основные ошибки, в общем, стоит ознакомиться.

18. Несколько советов по оптимизации UI

Раннее уже упоминали про Camera.main, но в новой статье описаны ещё несколько интересных особенностей оптимизации UI.

19. Сборник советов от FunCorp

Хорошая статья про оптимизацию UI. Многое уже описано тут, но есть и замечания по новым компонентам, например TextMeshPro.

20. Оптимизация UI без кода

Статья от Banzai Games про основные способы не делать неправильно Unity UI. Есть и интересные замечания. Зачем только снова про древний текстовый компоненты говорить... Думаю уже все перебрались на TMP.

21. Оптимизация мобильных 3D-проектов

Хорошая статья про оптимизацию в 3D. Многое подойдет и для 2D. Рассмотрены все аспекты и UI, и текстуры, шейдеры, батчинг и т. д.

22. Топ-10 ошибок в оптимизации Unity

Хороший вебинар от юнитеков, рассмотрены частые ошибки совершаемые при оптимизации, обзор инструментов по оптимизации, примеры с пояснениями.

23. Оптимизация игр на Unity: проверенный в деле план

Перевод отличной статьи по оптимизации игр на Unity. Как подготовиться к оптимизации, что лучше делать, что не делать, как правильно использовать профайле и многое другое.

Пока все. Тут не было про физику, потому что пока я ее не использовал. Возможно, в будущем добавлю. Пишите в комментариях ваши проверенные способы оптимизации для 2D игр под Unity.

 7 комментариев    13939   2016   android   ios   unity   игры   разработка

Unity Event Manager с параметрами

Обновлено 4.12.2017
Немного обновил этот пример — теперь в параметры и их количество могут быть любыми

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

Модернизируем немного пример с сайта:

using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
using System;

public class EventManager : MonoBehaviour {

	[Serializable]
	public class GameEvent : UnityEvent <string> {};	// Наше новое событие с параметром			
	private static EventManager _eventManager;								
	private Dictionary <string, GameEvent> _eventDictionary;				

	public static EventManager instance {
		get {
			if (!_eventManager) {
				_eventManager = FindObjectOfType (typeof (EventManager)) as EventManager;
				if (!_eventManager) 
					 Debug.LogError ("There needs to be one active EventManger...");
				else 
					_eventManager.Init (); 
			}
			return _eventManager;
		}
	}

	void Init () {
		if (_eventDictionary == null)
			_eventDictionary = new Dictionary<string, GameEvent>();
	}

	public static void StartListening (string eventName, UnityAction <string> listener) {
		GameEvent thisEvent = null;
		if (instance._eventDictionary.TryGetValue (eventName, out thisEvent))
			thisEvent.AddListener (listener);
		else {
			thisEvent = new GameEvent ();
			thisEvent.AddListener (listener);
			instance._eventDictionary.Add (eventName, thisEvent);
		}
	}
		
	public static void StopListening (string eventName,  UnityAction <string> listener) {
		if (_eventManager == null) 
			return;
		GameEvent thisEvent = null;
		if (instance._eventDictionary.TryGetValue (eventName, out thisEvent))
			thisEvent.RemoveListener (listener);
	}

	public static void SendEvent (string eventName, string param = null) {
		GameEvent thisEvent = null;
		if (instance._eventDictionary.TryGetValue (eventName, out thisEvent))
			thisEvent.Invoke (param);	// Вызов и передача параметра
	}
}

Вместо UnityEvent будем работать с GameEvent у которого теперь есть string. Таким же образом преобразуем UnityAction и функцию вызова события.

Пример использования такой же:

void OnEnable () {
	EventManager.StartListening ("event_name", MyFunction);
}

void OnDisable () {
	EventManager.StopListening ("event_name", MyFunction);
}

void MyFunction (string param) {
	Debug.Log (param); // переданный параметр
}

...

EventManager.SendEvent ("event_name", "param_string"); // вызов события

Собственно, параметров можно сделать несколько и других типов, всё зависит от потребностей.

 Нет комментариев    2939   2016   unity   разработка

Push-уведомления для iOS в Unity

Используя Unity для мобильной разработки, часто возникает необходимость добавить push-уведомления в свою игру или приложение. И если вы планируете выпускать игру для платформы iOS, то в Unity уже есть средства для работы с уведомлениями. Для Android нужно будет писать нативный плагин, об этом в другой раз.

И так, предположим серверная часть у вас уже готова, настроены сертификаты и т. д. Осталось сделать реализацию для приложения.

Первое, что нужно сделать — объявить, что вы хотите получать уведомления:

using NS = UnityEngine.iOS.NotificationServices;
using RN = UnityEngine.iOS.RemoteNotification;
...
void Awake () {
   NS.RegisterForNotifications(NotificationType.Alert|NotificationType.Badge|NotificationType.Sound);
   isTokenSent = false;
   isErrorAlert = false;
}

Так как, коллбеков никаких нет, что печально кстати, то проверяем все наши действия в Update:

void Update () {
   if (NS.registrationError != null && !isErrorAlert) { // проверяем есть ли ошибки
      Debug.Log (NS.registrationError);
      // что-то пошло не так
      _isErrorAlert = true;
   } else if (NS.deviceToken != null && !isTokenSent && !isErrorAlert) { // проверяем есть ли токен и отправлен ли он
      string token = Convert.ToBase64String (NS.deviceToken);
      SendTokenToServer (token); // отправляем токен на свой сервер
      _isTokenSent = true;
   }	
   if (_isTokenSent && !isErrorAlert && NS.remoteNotificationCount > 0) { // проверяем если есть токен, нет ошибок, и есть уведомления, то берем их
      RN push = NS.GetRemoteNotification (NS.remoteNotificationCount - 1);
      // делаем с нашим уведомлением что хотим и очищаем
      NS.ClearRemoteNotifications ();
   }
}

У объекта push есть свойство UserInfo в котором можно передавать с сервера нужные данные, а в приложении соответственно обрабатывать их. В документации также можно найти пример с локальными уведомлениями.

 Нет комментариев    1316   2016   ios   unity   разработка