2d urp unity что это
Перейти к содержимому

2d urp unity что это

  • автор:

Разработка мобильных игр на Unity. URP, 2D Animation и другие новомодные вещи на примере игры

Всем привет! Это снова Илья и сегодня мы поговорим о технической реализации мобильной игры в современных реалиях. Статья не претендует на уникальность, однако в ней вы можете найти для себя что-то полезное. А чтобы рассмотреть разработку на реальном проекте — мы возьмем реализацию нашей игры, которая на днях выходит в Soft-Launch.

Дисклеймер! Код в этой статье не проходил рефакторинг и носит лишь ознакомительный характер, чтобы поделиться идеями. И вообще, в целом, это smellscode.

Итак, запасаемся кофе, открываем Unity и погнали!

Базовая настройка проекта. URP и все-все-все.

Начнем с того, что мы работаем с URP (Universal Render Pipeline). Почему так? Потому что он проще в настройке и обладает более гибким контролем, чем стандартный рендер. Ну и добиться хорошей производительности на тапках исходя из этого — намного проще.

Стоит указать, что ниже пойдет речь о 2D игре. Для 3D игр подходы будут несколько отличаться, как и настройки.

Мы реализовали два уровня графики. Low Level — для деревянных смартфонов и High Level — для флагманов. Уровни графики подключаются при помощи Project Settings.

В нашем проекте стоят следующие настройки (для Quality уровней):

Настройки графики для пресета Low в Project Settings:

На что здесь следует обратить внимание:

  • Texture Quality — качество текстур. Для High — мы берем полный размер текстур, для Low — Четверть. Можно еще внести Middle пресет с дополнительным уровнем.
  • Resolution Scaling везде стоит 1 — мы берем это значение из URP Asset.
  • Все что связано с реалтаймом — отключаем.

Теперь перейдем к настройкам самих URP Asset. На что следует обратить внимание:

Для разных уровней качества можно установить Render Scale — тем самым снижая разрешение для отрисовки. Также незабываем про Dynamic / Static батчинг.

Adaptive Performance

Отличная штука для автоматической подгонки производительности мобильных игр (в частности для Samsung-устройств):

Другие полезные настройки:

  • Отключите 3D освещение, лайтмапы, тени и все что с этим связано.
  • Используйте для сборки IL2CPP — ускорьте работу вашего кода.
  • Используйте Color Space — Linear.
  • По-возможности подключите multithreaded rendering.

Игровой фреймворк

Едем дальше. URP и другие настройки проекта сделали. Теперь настало время поговорить о нашем ядре проекта. Что оно включает в себя?

Само ядро фреймворка включает в себя:

  • Игровые менеджеры для управления состояниями игры, аудио, переводов, работы с сетью, аналитикой, рекламными интеграциями и прочим.
  • Базовые классы для интерфейсов (компоненты, базовые классы View).
  • Классы для работы с контентом, сетью, шифрованием и др.
  • Базовые классы для работы с логикой игры.
  • Базовые классы для персонажей и пр.
  • Утилитарные классы (Coroutine Provider, Unix Timestamp, Timed Event и пр.)

Зачем нужны менеджеры?

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

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

AnalyticsManager.Instance().SendEvent("moreGamesRequested");

А уже сам менеджер распределяет, в какие системы аналитики, как и зачем мы отправляем эвент.

Базовые классы.

Здесь все просто. Они включают в себя базовую логику для наследования. К примеру, класс BaseView и его интерфейс:

namespace GameFramework.UI.Base < using System; public interface IBaseView < public void ShowView(ViewAnimationOptions animationOptions = null, Action onComplete = null); public void HideView(ViewAnimationOptions animationOptions = null, Action onComplete = null); public void UpdateView(); >>
namespace GameFramework.UI.Base < using System; using UnityEngine; using UnityEngine.Events; using DG.Tweening; internal class BaseView : MonoBehaviour, IBaseView < // Private Params [Header("View Container")] [SerializeField] private Canvas viewCanvas; [SerializeField] private CanvasGroup viewTransform; private void Awake() < // View Canvas Detecting if (viewCanvas == null) < viewCanvas = GetComponent(); if (viewCanvas == null) throw new Exception("Failed to initialize view. View canvas is not defined."); > // View Transform Detecting if (viewTransform == null) < viewTransform = GetComponent(); if (viewTransform == null) throw new Exception("Failed to initialize view. View transform is not defined."); > // On Before Initialized OnViewInitialized(); > public virtual void OnViewInitialized() < >private void OnDestroy() < viewTransform?.DOKill(); OnViewDestroyed(); >public virtual void OnViewDestroyed() < >public virtual void UpdateView() < >public bool IsViewShown() < return viewCanvas.enabled; >public void ShowView(ViewAnimationOptions animationOptions = null, Action onComplete = null) < viewCanvas.enabled = true; if (animationOptions == null) animationOptions = new ViewAnimationOptions(); if (animationOptions.isAnimated) < viewTransform.DOFade(1f, animationOptions.animationDuration).From(0f) .SetDelay(animationOptions.animationDelay).OnComplete(() =>< if (onComplete != null) onComplete(); OnViewShown(); >); > else < if (onComplete != null) onComplete(); OnViewShown(); >> public void HideView(ViewAnimationOptions animationOptions = null, Action onComplete = null) < if (animationOptions == null) animationOptions = new ViewAnimationOptions(); if (animationOptions.isAnimated) < viewTransform.DOFade(0f, animationOptions.animationDuration).From(1f) .SetDelay(animationOptions.animationDelay).OnComplete(() =>< viewCanvas.enabled = false; if (onComplete != null) onComplete(); OnViewHidden(); >); > else < viewCanvas.enabled = false; if (onComplete != null) onComplete(); OnViewHidden(); >> public virtual void OnViewShown() < >public virtual void OnViewHidden() < >> >

А дальше мы можем использовать его, к примеру таким образом:

namespace Game.UI.InGame < using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using GameFramework.UI.Base; using GameFramework.Components; using GameFramework.UI.Components; using GameFramework.Managers; using GameFramework.Models; using GameFramework.Models.Ads; using Game.Models; using GameFramework.Utils; internal class ToDoListView : BaseView < // View Context public struct Context < public Action onToDoListClosed; >private Context _ctx; // View Params [Header("View References")] [SerializeField] private Button closeButton; [SerializeField] private AudioClip clickButtonSFX; // Private Params private AudioSource _windowAudioSource; public ToDoListView SetContext(Context ctx) < _ctx = ctx; // Initialize Audio SOurce if (_windowAudioSource == null) < _windowAudioSource = transform.gameObject.AddComponent(); transform.gameObject.AddComponent().currentAudioType = GameFramework.Models.AudioType.Sounds; > // Add Handlers closeButton.onClick.AddListener(() => < _ctx.onToDoListClosed.Invoke(); PlayClickSoundSFX(); >); return this; > public override void OnViewDestroyed() < closeButton.onClick.RemoveAllListeners(); >public override void UpdateView() < >private void PlayClickSoundSFX() < if (_windowAudioSource != null && clickButtonSFX!=null) < _windowAudioSource.playOnAwake = false; _windowAudioSource.clip = clickButtonSFX; _windowAudioSource.loop = false; _windowAudioSource.Play(); >> > >

Классы для работы с контентом, сетью, шифрованием

Ну здесь все просто и очевидно. Вообще, у нас реализовано несколько классов:

1) Классы шифрования (Base64, MD5, AES и пр.)

2) FileReader — считывающий, записывающий файл, с учетом кодировки, шифрования и других параметров. Также он умеет сразу сериализовать / десериализовать объект в нужном формате и с нужным шифрованием.

3) Network-классы, которые позволяют удобно работать с HTTP-запросами, работать с бандлами / адрессаблс и др.

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

Утилитарные классы

Здесь у нас хранятся полезные штуки, вроде Unix Time конвертера, а также костыли (вроде Coroutine Provider-а).

Unix Time Converter:

namespace GameFramework.Utils < using UnityEngine; using System.Collections; using System; public static class UnixTime < public static int Current() < DateTime epochStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); int currentEpochTime = (int)(DateTime.UtcNow - epochStart).TotalSeconds; return currentEpochTime; >public static int SecondsElapsed(int t1) < int difference = Current() - t1; return Mathf.Abs(difference); >public static int SecondsElapsed(int t1, int t2) < int difference = t1 - t2; return Mathf.Abs(difference); >> >

Костыль Coroutine-Provider:

namespace GameFramework.Utils < using System.Collections; using System.Collections.Generic; using UnityEngine; public class CoroutineProvider : MonoBehaviour < static CoroutineProvider _singleton; static Dictionary_routines = new Dictionary(100); [RuntimeInitializeOnLoadMethod( RuntimeInitializeLoadType.BeforeSceneLoad )] static void InitializeType () < _singleton = new GameObject($"#").AddComponent(); DontDestroyOnLoad( _singleton ); > public static Coroutine Start ( IEnumerator routine ) => _singleton.StartCoroutine( routine ); public static Coroutine Start ( IEnumerator routine , string id ) < var coroutine = _singleton.StartCoroutine( routine ); if( !_routines.ContainsKey(id) ) _routines.Add( id , routine ); else < _singleton.StopCoroutine( _routines[id] ); _routines[id] = routine; >return coroutine; > public static void Stop ( IEnumerator routine ) => _singleton.StopCoroutine( routine ); public static void Stop ( string id ) < if( _routines.TryGetValue(id,out var routine) ) < _singleton.StopCoroutine( routine ); _routines.Remove( id ); >else Debug.LogWarning($"coroutine '' not found"); > public static void StopAll () => _singleton.StopAllCoroutines(); > >

Логика сцен

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

Каждая сцена — содержит в себе основной Installer, который помимо различных View, подключает логические блоки — своеобразные куски механик:

Эти куски механик последовательно выполняются, отдавая события OnInitialize, OnProgress, OnComplete. Когда последний блок сыграет свой OnComplete — он завершит работу сцены (закончит уровень).

Зачем это сделано?

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

Работа с контентом

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

Анимации в игре

Самый удобный для нас вариант — оказался из коробки. Мы используем систему для работы с костной анимацией от самой Unity:

Да, можно взять Spine, но у нас нет настолько большого количества анимаций, поэтому вариант от Unity — весьма оптимален.

Упаковка и сжатие

Все, что можно и нужно запихнуть в атласы — мы запихиваем в атласы и сжимаем. Это могут быть элементы UI, иконки и многое другое. Для упаковки атласов — используем стандартный Unity пакер из Package Manager (V1):

Локализация

Вся локализация базируется на JSON. Мы планируем отказаться от этого в ближайшее время, но пока что на время Soft-Launch этого хватает:

Работа с UI

При работе с UI мы разбиваем каждый View под отдельный Canvas. 99% всех анимаций работает на проверенном временем DOTween и отлично оптимизирован.

View инициализируются и обновляются по запросу через эвенты, которые внедряются в Level Installer, либо в отдельных блоках логики.

Что мы используем еще?

  • Salsa — для липсинка;
  • 2D Lighting — для освещения. В большинстве сцен используется освещение по маске спрайта;
  • DOTween — для анимаций;

Итого

Работа с механиками получается достаточно гибкой за счет блоков логики. Мы изначально думали взять связку Zenject + UniRX, но решили отказаться от нагромождения большой системы. Да, мы сделали проще, но нам и не нужно всех возможностей этих огромных библиотек.

Полезные ссылки:

Масштабируемая и высокая производительность рендеринга

Universal Render Pipeline от Unity стал мощным решением, сочетающим красоту, скорость и производительность, а также поддержку всех целевых платформ Unity.

See what’s new in URP in Unity 2022 LTS Learn more
Scalable visuals across all platforms

The Universal Render Pipeline is a multiplatform rendering solution built on top of the Scriptable Render Pipeline (SRP) framework. With scalability, customizability, and a rich feature set, URP offers you creative freedom in any type of project, from stylized visuals to physically based rendering.

Lost in Random scene

Lost in Random by Zoink Games

Первый взгляд на Universal Render Pipeline

  • Сравнение: Universal Render Pipeline и встроенный рендеринг
  • Поддерживаемые платформы
  • Больше выбора и контроля
  • Обновитесь сегодня
  • Обновитесь сегодня
  • Обновитесь сегодня

Lego Builder's Journey

LEGO® Builder’s Journey от Light Brick Studio

Universal Render Pipeline и встроенный рендеринг

Universal Render Pipeline
Упор на производительность
Однопроходный упреждающий рендеринг
Поддержка Shader Graph

Встроенный процесс рендеринга
Универсальность
Поддерживает как упреждающий, так и отложенный рендеринг

Mini Motorways Game

Mini Motorways by Dinosaur Polo Club

Поддерживаемые платформы

От 2D и 3D до AR/VR-проектов: Universal Render Pipeline позволяет не тратить время на доработку проекта для выпуска на новом устройстве.

  • Mac и iOS
  • Android
  • Xbox One
  • PlayStation 4
  • Nintendo Switch
  • Ведущие AR- и VR-платформы
  • Windows и UWP

Lost in Random: королева

Lost In Random от студии Zoink Games

Больше выбора и контроля

Возможность конфигурации рендеринга в Unity с помощью скриптов на C# позволяет вам:

  • оптимизировать производительность для конкретных устройств;
  • тонко настраивать процесс рендеринга в соответствии с конкретными требованиями;
  • управлять потреблением вычислительных ресурсов.

Circuit

Circuit Superstars by Original Fire Games

Обновитесь сегодня

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

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

Красивый снимок Gigaya

Artist-friendly features

To help with your transition from the Built-in Render Pipeline, URP offers numerous rendering capabilities, from Camera Stacking to Light Cookies and Point Light Shadows as well as renderer features such as Decals and Screen Space Ambient Occlusion (SSAO).

In addition, URP supports the latest node-based tools offered by Unity. Shader Graph allows you to visually author shaders in real-time. With VFX Graph, you can leverage the power of your GPU to create extraordinary VFX.

URP

Production-proven results

Thanks to its large platform reach, URP already powers numerous successful games, such as the relaxing puzzle platformer LEGO Builder’s Journey and the action-adventure game Lost in Random.

To help you start creating inspiring experiences in URP, discover the URP 3D Sample to learn how to create, customize, and scale beautiful graphics with flexibility and performance.

Основы настройки Universal Render Pipeline (URP) в Unity 2019.3

В этом статье вы узнаете, как начать работу с Universal Render Pipeline (далее «URP«) (для Unity 2019.3), который ранее известен как LWRP (Unity 2019.2 и ниже).

URP можно использовать практически на любой крупной платформе и обеспечивает красивую графику и высокую производительность.

Давайте попробуем преобразовать сцену из Unity в URP.

image

В первую очередь пойти в Windows — Package Manager и отсюда выберите Universal RP.

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

image

Первое, что вам нужно сделать — щелкните правой кнопкой мыши в иерархии проекта, чтобы создать файл настройки «URP» – Create – Rendering – Universal Render Pipeline – Pipeline Assets (Forward Render), а затем перейти к редактированию настройка проекта ( Edit – Project Settings — Graphics). Автоматически создастся два файла «URP» и «URP_Renderer».

image

image

И в разделе Scriptable Render Pipeline Settings выбрать «URP» который мы только что создали, и, как вы уже догадались, он преобразует все на сцене в розовый, потому что шейдеры по умолчанию не поддерживается в URP, но не волнуйтесь, мы исправим за одну минуту.

Чтобы преобразовать материалы перейти «Edit – Render Pipeline – Universal Render Pipeline – Upgrade Project Materials to UniversalRP», нажмите продолжить и вуаля, как вы можете видеть это не преобразовало все материалы отлично. Давайте посмотрим, как мы можем преобразовать другие материалы вручную.

image

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

Но не волнуйтесь, это просто прозрачная текстура травы, чтобы преобразовать этот материал надо изменить шейдер на «Universal Renderpipeline/Lit», далее «Render Face – Both», в Base Map выбрать текстуру для шейдера, включить Alpha Clipping, а Smoothness опустить на 0.

Ландшафт будет розовым, давайте исправим это.

Идем в папку материалов и создадим новый материал, щелкнуть правой кнопкой мыши Create — Material, который подпишу «Terrain», выберу тип шейдера «Universal Render Pipeline/Terrain/Lit» и после этого переместим его на место материала в terrain сцены.

Вы можете видеть, что наша местность снова отлично видна, но есть еще одна проблема, если вы заметили, наши ветви деревьев не отбрасывают тени, а ствол этих деревьев отбрасывает тень, чтобы решить эту проблему снова перейдите к материалу веток деревьев и из типа поверхности выбрать (surface type) прозрачный (transparent) и заменить на непрозрачный (opaque) и выставить Threshold на 0,5.

Если тени нету — перейдите в Directional light и измените Type — Directional, Mode — Mixed, Shadow Type — Hard Shadow, Dias — Use Pipeline Settings. Теперь они отлично отбрасывают тень.

image

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

Установка Mode — Global означает, что весь пост эффект будет применяться ко всей сцене, если вы хотите применить эффект к определенной области, то вы должны выбрать Local.
Далее добавим в Volume с помощью Add Override Bloom, White Balance, Depth Of Field, Shadows Midtones Highlights и Vignette добавляем при желании поиграть с цветами.

И, наконец, перейти к камере для её настройки что бы отобразить в полной мере пост эффекты и URP в сцене и окне пред осмотра игры. Изменим следующие настройки:

image

  • Render Type – Base,
  • Field of View – 45,
  • Render – Default Render (URP_Render),
  • Post Processing – поставить галочку,
  • Anti-aliasing – Fast Approximate Anti-aliasing (FXAA).

Также мы создадим три настройки графики для разных по силе устройств. Перейдем в ранее создан файл «UPR», изменим в Quality параметры по своему усмотрению, параметр Render Scale поможет существенно изменить производительность для слабых устройств, в Shadows измените дистанцию теней от 50 до 300 и добавьте каскады для теней что бы снизить нагрузку, остальные параметры можете оставить по умолчанию.

image

  • Universal Render Pipeline
  • URP
  • unity

Использование универсального конвейера рендеринга

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

Предыдущая версия URP называлась Lightweight Render Pipeline (LWRP). URP заменяет LWRP.

Информацию об использовании URP см. в документации по URP. микросайт

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *