Unity: Всё, что вы не знали о разработке – Telegram
Unity: Всё, что вы не знали о разработке
1.74K subscribers
40 photos
101 links
Авторский канал о разработке в Unity от Alex Silaev (CTO в Zillion Whales). Mushroom Wars 2 моих рук дело.
Рассказываю об интересный кейсах, делюсь лайфхаками, решениями.
Download Telegram
Про производительность

Мы знаем, что производительность - это метрика, которую можно оценить по fps или frames per second, т.е. сколько раз мы можем за секунду выполнить всю логику в кадре и отрисовать все, что мы посчитали.

Логика - это все то, что мы пишем в наших методах Update, которые являются частью основного цикла кадра и это обрабатывается на cpu, а вот рендер - это то, что обрабатывает видяха.

В целом эти два процесса никак не связаны, то есть в какой-то момент времени cpu посчитал что-то и готов передать на gpu некие данные, которые будут обрабатываться уже там и как результат - будет картинка. Существуют еще compute shaders, которые по сути используют проц на видяхе, чтобы посчитать результат.

И вот тут нам нужно синхронизировать данные. То есть при использовании синхронизации нам нужно задать фиксированное количество времени, которое мы готовы потратить на кадр, например, 30 кадров в секунду или 33мс на кадр. И при синхронизации существует время ожидания, когда cpu ждет gpu или наоборот. В профайлере такие ожидания обозначаются как WaitForPresentOnGfxThread. А вот WaitForTargetFps - это время, которое нужно, чтобы поддержать заданный frame rate.

#sync #gpu #cpu
👍22🔥6🥱3👾2
TypeCache API

Как-то не особо заметно прошло появление этого класса в юнити, но появился он аж в 2019.2.

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

https://docs.unity3d.com/ScriptReference/TypeCache.html

#editor #cache #types
🔥17👍5👾1
Extension и Receive

У меня все;)

#misspelling
😁8🤣2
this или не this - вот в чем вопрос.

Немного о себе 🙂
Я начал программировать лет в 10, а зарабатывать на этом в 14. С тех пор прошло уже больше 20 лет, мне будет уже 36 (ох, какой же я старый стал).

Начинал я с pascal в школе, там были ассемблерные вставки и я познакомился с man. Потом перешел на visual basic, на котором делал всякие интересные штуки, познакомился с winapi. С приятелем в школе нашли dark basic и стали на нем писать какую-то фигню, но дело быстро свернулось, в основном из-за непонимания происходящего и что такое update loop, в visual basic такого не было 🙂
Потом в универе занимался плюсами, года 4 на них потратил.

В последние годы универа увлекся php, настолько, что в итоге первая фултайм работа была связана именно с этим. Помимо php ессно я занимался разными бд, full-text-search движками и прочими штуками, т.к. без этого стека выжить было нереально.

Потом решил, что бэк - это уже не так интересно, в софт идти совсем не хотелось, а игры я тогда вообще не понимал как делаются (хотя под directx еще на vb писал какие-то штуки), поэтому пошел в понятную область - в js. Пытался рендер делать на js, но с приходом первого html5 - перестал пытаться.

И вот тут, как не сложно догадаться, я все же решился пойти в игры. Не буду описывать подробности этого непростого периода, но в итоге я нашел Unity (хотя даже тогда выбор был из нескольких движков, в том числе и UE). В Unity меня привлекли мобилки (хотя что я тогда о них знал, недавно только вышел iphone 3G) и самое главное - js. Да, я быстро понял, что это никакой не js, а скорее нечто среднее между js и action noscript, но Unity уже была скачана, первый видос на ютубе посмотрен, где человек упроно называл сцену "скин" (как сейчас помню), так что куда деваться - надо писать свою ММОРПГ (шучу, терпеть их не могу, если честно). Конечно же я начал делать свою RTS 🙂

Ну так вот. К чему я это все. Я писал this, пишу this и буду писать this.

#story #life #this
🔥36👍9🌚5👏3❤‍🔥2👨‍💻2👎1🥰1
Триангулятор

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

Суть сводится к тому, чтобы на выходе получить треугольники (как следует из названия) из точек. А для создания мешки нам нужны вертексы (те самые точки) и индексы (как именно эти точки образуют треугольники).

#triangulator #math #mesh
👍6🔥2👌2🥱2
Texture2D.GenerateAtlas

Я уже писал про PackTextures, но эта штука ломается, если невозможно запаковать текстуры, т.к. их размер превышает максимальный размер атласа. Для этого можно использовать GenerateAtlas, т.к. этот метод ничего не делает с текстурами, а только работает с ректами и возвращает true, если все объекты поместятся в атлас. То есть можно сначала вызвать его, а потом использовать PackTextures, либо запаковать самостоятельно, используя SetPixels.

#api #code #unity
🔥15👍3
Instantiate<T>()

Я часто встречаю в коде вот такой вариант:

var instance = Instantiate(prefabGo);
instance.GetComponent<MyComponent>();

Дело в том, что можно использовать такой вариант:

var instance = Instantiate(prefabMyComponent);

Который сразу вернет нам ссылку на инстанс нашего объекта.

#lifehack #basics #instantiate #code
🥱67👍18🔥6🥴5🌚1💯1
Год назад мы решили записать нашу главную тему игры в виде простого клипа:
https://www.youtube.com/watch?v=RtR4E0z5Sys
При этом музыканты - это все люди из нашей компании.

А вы делали что-нибудь подобное в своих студиях или проектах?
Делитесь ссылками в комментах!

#clip #video #soundtrack #mushroomwars2
🔥272🥰1
Для каких платформ вы делаете проект?
Anonymous Poll
41%
PC/Steam
54%
iOS
77%
Android
5%
Switch
6%
PS
6%
XBOX
16%
Другие
👍4🥰2🤨2🍓2
Может показаться, что я забыл (или забил) делать посты для канала, но на самом деле - нет, у нас просто релиз в этом месяце, а вы знаете как это запарно, ведь нужно успеть сделать 90% проекта за последние 2 недели.
На самом деле выходит очень даже неплохо и я обязательно поделюсь результатом, когда проект выйдет в релиз (будет софт).

#release #newproject #news
👍51🔥10🫡52👾2
Texture2DArray

Недавно столкнулся с проблемой, что у нас в проекте перестали влезать все юниты в один атлас, а нам прям надо, чтобы все юниты рисовались в один проход. Тут я вспомнил, что была такая древняя штука как Texture2DArray. Принцип простой: по сути у вас вместо 2д текстуры, она становится 3д, в шейдере нужны минимальные изменения для поддержки этого.

На практике же всплыло 2 проблемы:
1. Слои должны быть одного размера, т.е. нельзя сделать один слой 2к, а другой - 1к;
2. Эта штука не работает на андроиде.

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

#shaders #texture2darray #android
🔥8👍5🤯2
Есть такой мемчик, где люди делятся на 2 типа и вот это все. Ну там где у человека выключено отображение ворнингов и там где включено.
Я отношусь к тем, у кого они включены и вообще не люблю когда в логах мусор.

Так вот, в шарпе есть такая штука:

#pragma warning disable
#pragma warning restore


Она позволяет включать и выключать либо все ворнинги, либо конкретные, если указано какие конкретно нужно отключить.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#pragma-warning

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

Поддерживайте ваш код в чистоте и без лишних логов и предупреждений.

#logs #pragma #warnings
🔥15👍11😐3🤡1
В редакторе можно писать простые выражения в поля для чисел:
Например, чтобы сдвинуть объект, который находится в x=10, на 100 юнитов вправо, нужно написать 10+100 и нажать enter.

#editor #basics #formula
👍25🤡6🤯5🥴5🍓3
Array.Empty

Используйте вместо new T[0]; статичный массив, который не нужно создавать каждый раз.

#lifehack #optimization #basics
👍24😐8🔥3🗿2
ВОПРОСЫ

Тут можно задать вопрос или предложить тему для поста.
Старайтесь не разводить подтемы, чтобы это было удобнее читать и можно было найти.
Я закреплю это сообщение.

#questions
🔥7
memcmp

С помощью такой простой штуки можно определить насколько совпадают структуры между собой.
На практике такое я применяю для определения равны ли структуры (функция вернет 0) или же отличаются (функция вернет значение больше или меньше нуля, что покажет какая из структур "меньше").

#unsafe #memcmp
🔥14🤯5
Разбираемся с профайлером

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

WaitForTargetFPS: Время, потраченное на ожидание целевого значения FPS, указанного в Application.targetFrameRate. Редактор не использует VSync на GPU, а вместо этого использует WaitForTargetFPS для имитации задержки VSync.

Gfx.ProcessCommands: Поток рендеринга охватывает всю обработку команд рендеринга. Часть этого времени может быть потрачена на ожидание VSync или новых команд из основного потока, что можно увидеть в Gfx.WaitForPresent.

Gfx.WaitForCommands: Поток рендеринга готов к новым командам, и может указывать на узкое место в основном потоке.

Gfx.PresentFrame: Поток рендеринга представляет собой время, затраченное на ожидание рендеринга и представления кадра графическим процессором, что может включать ожидание VSync.

Gfx.WaitForPresent: Когда основной поток готов начать рендеринг следующего кадра, но поток рендеринга еще не завершил ожидание представления кадра GPU. Это может указывать на то, что узкое место в GPU. Посмотрите на представление временной шкалы, чтобы узнать, проводит ли поток рендеринга одновременно время в Gfx.PresentFrame. Если поток рендеринга все еще проводит время в Camera.Render, узкое место в CPU, т.е. тратит слишком много времени на отправку вызовов отрисовки/текстур на GPU.

#profiler #profiling #performance #gpu #cpu
👍37🔥141😐1
Fluent-interface

Вы, наверное, слышали и встречали такую штуку, а некоторые даже писали.

instance.Method1().Method2()

По своему определению текучие интерфейсы представляют из себя набор методов, где каждый метод добавляет или удаляет какое-то свойство, то есть меняет инстанс.
В принципе я с этим не совсем согласен. Я считаю, что такие методы должны ставить флаги (или просто записывать входные параметры), то есть не должны выполнять работу прямо в месте вызова.

Как?
Ну это довольно просто:
void Method() {…}
Меняем на
T Method() { return this; }
Где T может быть текущим типом, может быть интерфейсом (как в оригинале было и задумано, но структуры все портят).

Где?
Я использую такое в API своих ME.ECS/BECS для сборки фильтров и запросов.
Вне ecs я передаю настройки в виде структуры, которую я собираю как раз через такой подход. Ну и твинер у нас написан с таким же походом.

Зачем?
Лаконичность кода и легкость восприятия.

Пишите в комментах где вы используете fluent-interface подход.

#architecture #fluent #interface
👍6🔥5🥴4🐳2🤡1
AOT статик методы для компиляции

Совсем недавно ко мне обратился коллега с просьбой помочь с ошибкой, когда json не мог распаковаться и падал с ошибкой примерно такой по смыслу:
"Не могу найти конструктор с передаваемыми параметрами", а стек показывает, что где-то там через рефлексию создается инстанс (через Activator) и при вызове конструктора чет все падает.

И тут знаете, как в шуточках за 300, люди делятся на несколько групп:
1. Неопытные с ужасом идут гуглить ошибку, ничего не находят, идут дергать вторую группу;
2. Более опытные понимают, что тут как-то не очень все тривиально, идут в место где рефлексией создается какой-то объект и пытаются понять как же можно было накосячить создателям плагина, что оно не работает;
3. Ну и такие как мы с вами, которые в принципе уже понимают, что билд скорее всего il2cpp, что рефлексия - это плохо, что il2cpp ничего об этом знать не знает, а значит проблема просто в том, что метода нет после компиляции.

К чему я это все. Для исправления подобных ситуаций, il2cpp нужно "подсказать", что существует метод (или конструктор), для чего я обычно делаю в проекте файл AOT.cs:


public static class AOT {
[Preserve]
public static void Dummy() {
new SomeClass().Method(); // не вырезаем конструктор и метод из билда
...
}
}


Т.е. мы никогда не вызываем этот метод, но при сборке эти методы будут добавлены.
Вообще это касается всех вызовов через reflection и когда в проекте не указывается вызов.

#aot #il2cpp #error
🔥38👍9