TGViewer
Channel Public Channel
SpellSinger - разработчик игр на Unity

SpellSinger - разработчик игр на Unity

@spellsingergames

Привет! Я Денис и я делаю игры на Unity. В этом блоге я делюсь своим опытом в геймдеве и не только.

Навигация в закрепе: https://t.me/spellsingergames/3

Написать в личку: @sinedsem
Subscribers
548
Photos
90
Videos
22
Links
105

Showing posts older than #44 · Back to latest

Older Posts 19 shown
Post #43 2.05K
Оптимизации в Бурить-Копать!

Поделюсь списком оптимизаций, которые я сделал в нашей игре. После этих оптимизаций FPS на слабом тестовом устройстве поднялся с нестабильных 20-30 до стабильных 40+.

По традиции, рассказываю только то, что мне было не очевидно ранее, то есть делюсь свежайшим опытом.

1) Разделил UI на несколько отдельных Canvas'ов. Смысл был в том, чтобы вынести кликабельные элементы (кнопки) в отдельный Canvas, и только на него повесить Graphic Raycaster, а так же в том, чтобы отделить UI-элементы, которые перерисовываются часто, от тех, которые перерисовываются редко.

2) Снял галочку Raycast Target на некликабельных элементах, но только на тех Canvas, на которых остался Graphic Raycaster. У TMP Text снял все лишние галочки типа Rich Text, а так же постарался избавиться от функции Auto Size, она очень прожорливая.

3) В компоненте камеры Physics 2D Raycaster выбрал только один слой, на который добавил только те объекты мира, по которым можно кликнуть (у меня их всего 2).

4) В CinemachineBrain выбрал Update Method - Smart Update (по умолчанию у меня было Fixed Update, и оно больше тормозило).

5) Отключил все неиспользуемые Unity пакеты. Не уверен, что это повлияло на производительность, но точно повлияло на размер билда.

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

7) Начал использовать батчинг при работе с Tilemap. Раньше я задавал каждый тайл отдельно через Tilemap.SetTile, теперь я генерирую всю строчку целиком, и вызываю Tilemap.SetTiles. Это дало очень большой прирост производительности.

8) Разобрался со взрывом динамита. Там, кроме всего прочего, была вспышка, сделанная с помощью Particle System. Проблема была в том, что во время первого взрыва игра сильно подтормаживала, а на последующих все было норм. Я сделал warmup шейдера, который использовался для вспышки (Additive), но это не помогло. Профайлер показал, что именно сама система частиц долго стартует в первый раз, и мне пришлось добавить искусственный прогрев частиц - я взрываю один динамит в самом начале игры, без звука и за границами камеры.

#performance
  • 🔥 11
Post #42 756
По просьбе подписчиков добавил кнопку выбора папки в импортер спрайтов.

Пишите в чат, если у вас есть предложения или замечания, по мере возможностей буду улучшать свои самоделки.
  • ❤ 2
  • 👍 1
Post #41 891
Очень достойная статья про разработку веб-игр для Яндекса от Чики. Жалею, что не увидел её раньше, многие проблемы пришлось решать самостоятельно.

https://telegra.ph/100-i-1-problema-Unity-v-WebGL-07-17
Telegraph 100 и 1 проблема Unity в WebGL Статья удалена. Актуальную информацию вы сможете найти в нашей группе: https://t.me/chikadev. С уважением, Чика.
  • 👍 5
Post #40 2.06K
Удобный импорт спрайтов [Бесплатные расширения для Unity]

Пример использования на видео (обязательно посмотрите)

Возможности:
- Импорт отдельных картинок покадровой анимации с объединением в одну текстуру
- Автоматическая разметка импортированной текстуры на спрайты
- Отступы между спрайтами
- Настройка количества столбцов
- Можно сделать текстуру квадратной
- Выбор папки, выбор имени
- Можно импортировать не все спрайты из папки, а с префиксом
- Отдельная логика для импорта кнопок, кнопки сортируются в порядке обычная/подсветка/нажатая/выключенная (исходные файлы должны быть правильно названы)
- Настройка pixels per unit
- При первом импорте можно указать pivot для спрайтов, последующие импорты используют pivot из существующей текстуры

Инструмент находится в меню Window/SpellSinger/Sprite Animation Importer

Чтобы забрать себе, добавьте Unity пакет по ссылке:
https://github.com/SpellSingerGames/sprite-animation-helpers.git
[Window/Package Manager/+/Add package from git URL...]

#selfmade #самый_крутяк #2d
  • 🔥 8
Post #39 652
Выступил на питчине от сообщества Indie Go, рассказал про нашу игру в разработке, Бурить-Копать!

Кстати, есть запись, https://vk.com/video-214798851_456239040 (я первый)

#бурить_копать
  • 🔥 5
  • 👍 1
  • 👏 1
Post #37 624
Очень советую подключать стороннюю аналитику, мне очень нравится GameAnalytics. Пока Яндекс пишет, что у меня 6 игроков, я уже вижу, что их 16

#sneaky_forest #веб_игры
  • 🔥 6
Post #36 643
Мы релизнули нашу игру Sneaky Forest в Яндекс Играх. Будем наблюдать за органикой Яндекса, потом расскажу об успехах.

Модерацию прошли со второго раза, в первый раз было 3 замечания:
1) В описании упоминался ИИ, заменили на слово "противник"
2) Залили промо-видео, записанное на русской версии игры, в английский язык. Не прокатило, заметили, попросили, чтобы промо-видео было на английском.
3) Была загружена зацикленная гифка на пару секунд. Не прокатило. Вообще, с промо-гифками полные непонятки, не указаны требования ни по ФПС, ни по минимальному разрешению, зато ограничены весом в 600кб. Мы просто удалили гифку, она не обязательная, и не понятно, где она будет использоваться. Кажется, видео вполне хватит.

#sneaky_forest #веб_игры
  • 🔥 9
Post #34 584
Сибирский джем запустили конкурс вместе с Яндекс Играми. Так как наша игра "Бурить-Копать!" ещё не готова, будем участвовать в конкурсе с нашей старой игрой, сделанной как раз на сибирском джеме, Sneaky Forest. Заодно получим первый опыт публикации, модерации и т. д.

Буду держать в курсе!

#sneaky_forest #веб_игры
  • 🔥 2
Post #33 659
photo_2023-11-17_23-11-12.jpg70.4 KB
Проблема с отображением русских символов в TextMeshPro

Ещё один секрет, на этот раз от Марго. Если некоторые или все кириллические символы отображаются квадратиками, нужно в настройках шрифта указать правильный диапазон символов (Character Set, Character Sequence). Нужный диапазон для кириллицы: 0400-04FF. Не забудьте применить изменения с помощью кнопки Save (она внизу, её может не быть видно из-за скролла)

#ui #TextMeshPro
  • 🥰 5
  • 👍 4
  • 🔥 1
Post #32 897
Эффект набора текста (печатной машинки)

Это эффект, когда текст появляется не сразу, а побуквенно. Может использоваться, например, в диалогах.

Один из способов сделать такой эффект, это, например, сделать окончание текста прозрачным с помощью тега <color=#FFFFFF00>. Этот способ описывается, например, тут. Мне он не очень понравился, потому что имеет ограничения, например, он не применим, если в тексте уже есть разметка (особенно другие цвета).

Мне посоветовали (зрители моего стрима) посмотреть на вот этот ассет, из которого я взял самую суть и делюсь ей с вами:

private IEnumerator DoType()
{
var totalVisibleCharacters = tmpText.GetParsedText().Length;
for (var i = 0; i <= totalVisibleCharacters; i++)
{
tmpText.maxVisibleCharacters = i;
yield return new WaitForSeconds(delay);
}
}


То есть, мы используем свойство TMP maxVisibleCharacters, которое позволяет ограничить количество отображаемых символов, и метод GetParsedText(), чтобы получить итоговое количество символов, которое мы хотим показать (без учёта тегов).

#ui #effects #TextMeshPro
  • 👍 8
  • 💩 2
Post #31 977
Почему я думаю отказаться от Zenject в следующей игре

Причём я собираюсь отказаться именно от Zenject, но не от DI. DI это удобно и ускоряет разработку, и у меня не было с ним проблем ни в геймдеве, ни в основной моей работе на Java.

Основная причина отказаться от Zenject – это то, что он больше не поддерживается. Последний коммит в его репозиторий был 6 апреля 2021 года. Обычно я проверяю, не заброшена ли технология, перед тем, как её использовать, но Zenject был у меня на слуху, и я взял его не глядя.

Заброшенные библиотеки/фреймворки имеют свойство устаревать в какой-то момент. Либо они перестают быть совместимы с версией движка/ЯП, либо в них обнаруживается критический баг, который уже никогда не будет исправлен.

Сейчас смотрю в сторону VContainer. В нем нет своей шины событий, и нет пулов, но зато он не заброшен, да ещё и обещает большую производительность.

А с самим Zenject'ом у меня проблем не было, хотя мое скромное время использования конечно не особо показательно.

#zenject
  • 👍 1
  • 🔥 1
  • 😢 1
Post #30 969
Зачем я использую Zenject. Часть 3. Пулы

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

Сначала я использовал свою реализацую пулов, но когда перешел на Zenject, и захотел, чтобы в новые объекты можно было внедрять зависимости - я перешёл на Zenject-ные пулы. Они довольно удобные.

Кстати, я написал «для однотипных врагов», потому что в пуле могут быть объекты только одного типа, полученные из одного префаба, которые можно минимальными усилиями кастомизировать под конкретную ситуацию.

P. S. Следующий пост про то, почему я теперь думаю не использовать Zenject в следующем проекте.

#zenject
  • 👍 4
  • 🔥 1
Post #29 1.38K
Зачем я использую Zenject. Часть 2. События

В Zenject событие называeтся Signal, очевидно, это сделано для того, чтобы не было конфликта с зарезервированным в C# словом event.

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

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

В моей игре, уровень начинается с того, что игрок нажимает кнопку влево или вправо. За ввод данных (player input) отвечает один монобех, PlayerController, который знает, когда уровень начался или ещё нет. Он и "бросает" событие PlayLevel.

Есть ряд действий, которые нужно выполнить в тот момент, когда начинается уровень:
- Камера переходит из начального положения в игровое положение (меняется offset)
- Изменяется фоновая музыка
- С экрана убирается подсказка
- Запускается процесс потребления топлива

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

В пользу Zenject'а по сравнению с событиями, реализованными с помощью Scriptable Objects, замечу, что с Zenject
1) мне не нужно присваивать значения в инспекторе, всё происходит в коде
2) я могу легко найти все места, где используется какое-то событие в IDE, поиском по местам использования класса PlayLevel

#zenject
  • 🔥 3
  • 👨‍💻 1
Post #28 1.05K
Зачем я использую Zenject. Часть 1. Внедрение зависимостей

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

Для себя я каждый день извлекаю пользу от Zenject в том, что я пишу в любом компоненте [Inject] private Foo foo; и сразу же получаю себе зависимость Foo;

В чем плюсы:
+ Мне не нужно париться с назначением зависимостей в инспекторе.
+ Мне не нужно делать зависимости синглтонами в классическом их понимании, со статической ссылкой на инстанс.
+ И да, если однажды мне понадобится 2 разные реализации Foo, я сделаю Foo интерфейсом, сделаю 2 реализации, буду их подсовывать через Zenject, а пользователи Foo даже и не заметят разницы.


#zenject
  • 👍 5
Post #27 509
Как написать сложный алгоритм?

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

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

Как только я поменял модель данных, вместо "метров" стал думать "участками пути", код сам стал вытекать из моих пальцев.

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

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

По моим наблюдениям, чем лучше модель данных, тем проще писать код. А значит, если код "не идёт", стоит проверить, а так ли хороша модель.

#программирование
  • 🔥 4
  • 👍 3
  • 🗿 1
Post #26 1.84K
Про звуки в мобильном Яндекс Браузере

На момент написания этого поста в мобильном Яндекс Браузере не работают звуки из Unity, и для того, чтобы опубликоваться в Яндекс Играх, нужно городить костыли.

Я немного покопался, и выяснил, что не работают звуки, которые весят меньше 128кб. Почему - не знаю, но если взять длинную музыку, которая работает, и начать отрезать её по чуть-чуть, то в какой-то момент, а именно при весе меньше 128кб она перестаёт воспроизводиться.

Так как все разработчики сталкиваются с этой проблемой, в сообществе разработали решение: Unity Audio Plugin (документация, канал разработчика, чат разработчика).

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

К сожалению, в текущей версии плагина 3.0.4 есть баг, в результате которого звуки ломаются после паузы (звуки должны ставиться на паузу, когда окно игры становится неактивно или показывается реклама).

Я думаю, что в будущем разработчик поправит эту проблему (я о ней уже сообщил и сказал как решить), но если вы хотите решить её самостоятельно, то в классе StreamingAudioProvider замените строчки 114-117, чтобы получилось вот так:

_unitySource.clip = _clip;
_unitySource.time = _lastTime = 0;
_unitySource.Play();
_beginPlaying = true;


Если что-то не получится, пишите мне в комментарии, помогу чем смогу.

#яндексигры #репорчу_баги
  • 🔥 5
  • 👍 2
Post #25 1.13K
Черный фон при изменении размеров игры в браузере

Если у вас такая же проблема, как в примере на видео, то вам нужно пойти в Player Settings > Other Settings > Rendering и в настройке Color Space выбрать Gamma вместо Linear.

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

Пример на видео найден случайным образом в новинках Яндекс.Игр

#bugs_and_fixes
  • 🙏 4
  • 🔥 1
Post #24 483

Forwarded from Яндекс Игры

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

Отметим, что сейчас эта панель работает в тестовом режиме. Постараемся доработать этот момент в будущем. Спасибо, что подсветили.
  • 🔥 6
Post #23 508
Продолжаем дорабатывать платформу Яндекс.Игры путём активной гражданской позиции 😄

#репорчу_баги
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →