Давайте посмотрим, как делать внутриигровые скриншоты, чтобы увековечить свои дикие приключения!

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

Например, хотя события Marvel's Spider-Man и Shadow of Mordor происходят в совершенно разных контекстах, обе игры предлагают изысканный и увлекательный режим изображения, который замораживает действие и позволяют сделать снимок в середине сцены действия.

Что, если бы вы могли делать это и в своих играх на Unity? Сложно реализовать? Спойлер: не совсем так! :)

Итак, сегодня мы увидим:

  • 🛠 как настроить фоторежим
  • 🔍 как войти и выйти из этого режима с базовым интерфейсом
  • 📷 как сделать скриншот и сохранить его на диск

Вы готовы? Тогда вперед!

🛠 Настройка нашего фоторежима

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

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

… например, в нашем случае можно было попросить просто сохранить изображение куда-нибудь на диск! :)

Допустим, у меня есть основная камера в моей сцене Unity, которая отображает базовую демо-сцену, и простой контроллер FPS для моего персонажа (это взято непосредственно из базового стартового пакета Unity для FPS, доступного бесплатно здесь):

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

Здесь мы хотим иметь возможность нажать какую-нибудь клавишу, например <P> (для «изображения»), чтобы войти в фоторежим. В этом режиме камера будет заблокирована в текущем положении, и у нас будет две кнопки, чтобы либо сделать снимок экрана (и выйти из режима фото), либо напрямую выйти из режима фото.

Давайте создадим скрипт C# с именем PhotoMode и добавим его в префаб нашего плеера: это игровой объект с именем «PlayerCapsule» в демо-сцене. Если вы откроете его в IDE, вы увидите, что на данный момент он содержит класс MonoBehaviour по умолчанию, который Unity автоматически генерирует для любого нового скрипта:

Для начала давайте изменим нашу функцию Update(), чтобы она проверяла наш ввод с клавиши <P>. Если мы действительно нажимаем эту клавишу, то мы хотим войти в фоторежим с помощью функции _EnterPhotoMode():

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

Теперь, чтобы заморозить камеру, мы собираемся сделать две вещи:

  • один, мы полностью отключим скрипт контроллера FPS. Это не даст нам ни двигать игрока, ни камеру и имитировать эту «заморозку».
  • во-вторых, мы установим глобальную переменную Time.timeScale в 0. Если вы точно не знаете, что делает эта переменная, не стесняйтесь взглянуть на эту недавнюю статью, которую я написал на эту тему :)

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

Кроме того, поскольку сценарии стартового пакета находятся в пространстве имен StarterAssets, нам нужно сначала импортировать его с ключевым словом using:

Если вы попробуете это сделать, вы увидите, что как только вы нажмете клавишу <P>, экран зависнет, как и ожидалось! За исключением того, что на данный момент у нас нет возможности выйти из этого режима…

🔍 Добавление пользовательского интерфейса и выход из фоторежима

К счастью, это довольно легко решить :)

Сначала нам нужно добавить две кнопки на Canvas (здесь я поэкспериментировал со спрайтами пользовательского интерфейса из стартового пакета и добавил несколько дополнительных значков):

Затем мы можем подготовить две общедоступные функции в нашем скрипте PhotoMode для каждой из этих кнопок:

И, наконец, вернувшись в редактор, мы можем перейти к инспектору каждой кнопки и добавить обратный вызов с соответствующей функцией:

Теперь в нашем скрипте PhotoMode мы собираемся добавить общедоступную ссылку на нашу родительскую панель пользовательского интерфейса «PhotoMode»: это упростит отображение или скрытие всего пользовательского интерфейса одновременно.

Примечание: не забудьте перетащить ссылку в инспектор после перекомпиляции скрипта! :)

И последнее, но не менее важное: поскольку контроллер FPS управляет мышью, по умолчанию он скрывает указатель. Таким образом, несмотря на то, что у нас есть пользовательский интерфейс, на который можно щелкнуть, в настоящее время у нас нет мыши, чтобы навести на него курсор! Чтобы решить эту проблему, нам нужно добавить небольшую строку в наши функции входа/выхода:

Обязательно сначала отключите панель пользовательского интерфейса — затем, если вы запустите игру, вы увидите, что нажатие <P> вызывает пользовательский интерфейс и останавливает игру, а затем нажатие крестообразной кнопки в правом нижнем углу возвращает к обычному режиму. режим:

📷 Скажи «сыр»!

Хорошо, наконец-то мы здесь: нам нужно разобраться со скриншотом экрана.

Вкратце идея состоит в том, чтобы:

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

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

Третий шаг в основном касается передачи и преобразования данных из одного формата в другой — я не буду вдаваться в подробности здесь, но не стесняйтесь просматривать различные темы в сети, в которых обсуждается этот вид преобразования; )

В общем, вот функция, которая будет делать скриншоты:

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

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

Если я попробую это, тадаа! Я получаю хороший скриншот моего текущего вида :)

Окончательный сценарий

Если вы хотите попробовать это сами, вот окончательный сценарий PhotoMode C#, который необходимо добавить к игровому объекту «PlayerCapsule»:

Вывод 📸

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

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

Надеюсь, вам понравился урок, и, как обычно, большое спасибо за чтение :)

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