Введение

Продолжение предыдущей статьи.

Это отчёт о разработке моего четвёртого майлстоуна. Я подвёл итоги ещё одного месяца работы. В этот раз основное внимание было уделено расширению систем и контента игры. Вот что было сделано:

  • Игровые системы
    • Слои фоновых объектов
    • Оптимизация путём замены шейдера
    • Окно настроек, доступное через pinch-to-zoom
    • Взаимодействие объектов с помощью процедурной анимации
  • Добавленные объекты
    • 2 вида зданий, играющих роль заднего плана

Архив

settings-testЗапись процесса тестирования входа в настройки

Создание ассетов

Изображения

pigeon-diggingpigeon-diggingГолубь, клюющий землю

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

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

Шейдер

Более подробно об этом ниже, но из-за проблем с нагрузкой на GPU я заменил используемый шейдер 2D-спрайтов на более лёгкий. Проблема в том, что этот шейдер не умеет отбрасывать тени (Cast shadow), и в нём не работает эффект глубины резкости (DOF) от пост-обработки. Было бы хорошо это исправить, но я пока не освоил шейдеры в достаточной мере, так что придётся либо уделить этому время, либо отказаться от некоторых визуальных эффектов.

Процесс разработки

Настройки в стиле камеры

settings-activatedВход в настройки через pinch-to-zoom. Пока прототип.

Окно настроек сделано без отдельного UI, чтобы максимально сохранить чистоту экрана и создать интересный эффект. Доступ к настройкам осуществляется с помощью pinch-to-zoom. Жест работает ступенчато: в определённом диапазоне это обычное увеличение/уменьшение масштаба камеры, а при превышении порога с вибрационным откликом открываются настройки. Выйти из настроек можно обратным жестом — pinch-in.

UI настроек выполнен в виде камеры. Иногда, фотографируя, я испытывал чувство, проходящее через экран в руке между мной и объектом съёмки — словно граница исчезает и сцена соединяется реалистично. Мне захотелось воспроизвести это ощущение.

Батарея и время отображаются с помощью SystemInfo.batteryLevel и DateTime.Now, показывая реальное состояние аккумулятора и время. Выдержка и диафрагма будут управлять эффектами пост-обработки — размытием движения и глубиной резкости.

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

Применение процедурной анимации

people-staring-pigeonsЕсли рядом голубь, персонаж на него смотрит

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

В отличие от голубя, у человека голова, тело и ноги — отдельные объекты. С помощью компонента Multiple Aim Constraint из пакета Animation Rigging я в качестве эксперимента реализовал, как голова персонажа поворачивается в сторону голубя, находящегося в определённом радиусе.

public void ChangeSourceObject(GameObject discoveredObject)
{
    WeightedTransformArray sourceObjects = Constraint.data.sourceObjects;
    WeightedTransformArray newSourceObjects = new WeightedTransformArray(sourceObjects.Count);
    
    newSourceObjects[0] = new WeightedTransform();
    WeightedTransform wt = newSourceObjects[0];

    /* ... */

    newSourceObjects[0] = wt;
    
    data.sourceObjects = newSourceObjects;

    Animator.enabled = false;
    rigBuilder.Build();
    Animator.enabled = true;
}

Чтобы реализовать эту функцию, нужно было заменить свойство sourceObject компонента Multi Aim Constraint на объект внутри сцены. Этот процесс оказался полным трудностей. Если кому-то понадобится программно менять sourceObject процедурной анимации, вот что может пригодиться:

  • Свойство sourceObjects — только для чтения (read-only). Нужно определить данные в другой локальной переменной, затем присвоить новое значение data.sourceObjects.
  • После присвоения необходимо отключить аниматор объекта, собрать rigBuilder, а затем снова активировать анимацию, чтобы изменения применились корректно.
  • Если какой-то объект зарегистрирован как sourceObject другого объекта, при его удалении следует изменить свойство sourceObject на None.

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

Попытка оптимизации с помощью Profiler

profilerПример данных, измеряемых Unity Profiler

Моя игра, как ни странно, после сборки сильно нагревалась и не могла поддерживать стабильные 40 FPS. Даже если мой код был неидеален, я старался избегать тяжёлых функций вроде GetComponent() и Find(), а код с циклами (for, foreach, корутины) писал так, чтобы он не выполнялся без необходимости. Но я никак не мог понять, почему 2.5D-проект, который должен быть лёгким, теряет частоту кадров.

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

В моём случае Semaphore.WaitForSignal занимал от 50 до 70% времени. Прочитав, что в такой ситуации рекомендуется заменить шейдер на более лёгкий, я заменил ранее найденный шейдер на более лёгкий. Частота кадров заметно выросла, а нагрев значительно снизился.

Критерии релиза

Необходимость цели для завершения

Создание анимаций и взаимодействий для разных объектов — это, в целом, увлекательное и интересное занятие, но я чувствовал, что оно отнимает гораздо больше времени и сил, чем я думал. Я надеялся, что с опытом эффективность работы вырастет, и она действительно выросла, но написание кода и создание покадровой анимации всё равно требуют минимального физического труда — набора текста или рисования линий на экране.

По мере роста проекта и увеличения количества ассетов я начал ощущать, что нагрузка становится всё больше. Помню, как в отчёте игровой индустрии, опубликованном Unity, я читал совет: «Don’t bite off more than you can chew». Я задумался, не движется ли моя ситуация в этом направлении.

Поэтому я решил, что нужно определить критерии релиза как целевой ориентир. На данный момент я решил поставить цель — подать заявку на Google Featuring. Google Featuring устанавливает чёткие критерии для высококачественных приложений и игр, среди которых:

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

Прочие собственные критерии

  • Приложение
    • Иконка приложения
    • 3D-звук
    • Простое обучение
    • Локализация текста в приложении
  • Объекты
    • Не менее 5 видов объектов
    • Не менее 2 вариантов индивидуальности на объект
    • Не менее 3 видов взаимодействия на объект
  • Окружение
    • Система погоды (дождь, снег и т.п.)
    • Динамическое небо с облаками
    • Гарантированное наличие на экране не менее 3 фоновых объектов

Заключение

gantt
    title Первая дорожная карта

    Section Планирование
    Планирование :a1, 2024-02-28, 1d

    Section Разработка
    Разработка прототипа :a2, 2024-02-28, 85d
    Визуальное оформление: a3, 2024-05-23, 10d

    Section Релиз
    Релиз и поддержка :a4, 2024-06-01, 213d

    %% a2["Завершение прототипа"] : разработка и тестирование функциональности начальной версии прототипа.

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

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