BluePrint UE4

BluePrint — визуальная среда для упрощения программирования, построенная на встроенных командах движка Unreal Engine, на С++ BP — очень мощный инструмент. Вообще, BP использует функции, написанные на C++, которые, кстати, довольно легко найти, если покопаться в движке. На самом то деле, мы пишем не на чистом C++, а используем его синтаксис, разные особенности, используя SDK движка. Ну где вы видели, например, класс Character или структуру FRotator в чистом C++? Собственно, в BP реализовали циклы, математические операции, функции, переменные и разное прочее, привязав SDK движка, чтобы можно было обходиться без Visual Studio. Даже если вам не хватает того функционала, что идет телегой с движком, вы всегда можете написать свой плагин для движка на C++, в который можно включить свои библиотеки и код на чистом C++ и настроить все так, чтобы движок видел все функции и предоставлял их использование в редакторе BP.  Тут уже дело удобства. Просто, как я, опять же, писал ранее, BP может разрастись в не хилую паутину, в которой будет уже довольно трудно разобраться. BP можно раскидать по функциям, которые тоже создаются в BP. Но есть некоторые задачи, которые не очень удобно решаются (или вообще не решаются) использованием BP. Серьезно, это очень мощный инструмент и при работе с этим движком вы никуда не денетесь от использования BP.

С++ является внешним языком программирования и не зависит от движка. Кроме того сам движок скомпилирован в среде С++. А вот BluePrint — это уже внутренние команды движка. Они довольно ограничены и не имеют доступа к файловой системе пользователя, а также к данным системы, таким как: объём памяти ОЗУ, названию видеоадаптера и т.д. Важное отличие от С++ — BluePrint имеет очень интересную графическую отладку, позволяющую легко находить неисправности в логике. Выглядит это в реальном времени словно ток бегущий по проводам от одной ноде к другой.

Медленнее ли BluePrint чем С++? BluePrint не медленный, просто он выполняются на время разработки игры в среде движка, соответственно происходит виртуализация и процессы обработки кода немного (или много, зависит от правильности логики кода) замедляются. Но стоит вам скомпилировать ваш проект и запустить. Как BluePrint уже в нём не будет. Там не будет даже С++, а будет Ассемблерный код. Естественно избавившись от виртуализации движка, игра будет работать гораздо быстрее чем в движке.

Можно ли расширить возможности BluePrint? Действительно можно, но для этого пишутся специальные плагины в среде С++. Они бывают двух типов:
1) Требуют наличие студии для компиляции проекта. Пример Substance Plugin.
2) Не требуют студию и свободно компилируется в проект без её наличия. Пример Rama Plugins с пропиской BP. Или в документации к плагину указывается что это для BluePrint проектов.

Для чего нужно нажимать кнопку Compile перед запуском игры? Дело в том что каждой ноде соответствует определённая команда (или набор команд) на С++. Для запуска симуляции игры в движке, требуется перевести нодовую логику (BluePrint) в С++ , что как раз и происходит после нажатия кнопки Compile. Скорость компиляции зависит от количества нод и от корректности логики. В случае нарушения логики при компиляции будет указано на место где есть ошибка.

Во всех BluePrint Function имеются проверки, которые не нужны в С++. Допустим PrintString в BluePrint та же функция AddScreenMessage как в С++, но с 5-ю проверками виде if(Branch) и других. После компиляции проекта они не убираются. В следствии в огромной логике BluePrint’тов время просчета кадра увеличиться. Но чаще всего основную нагрузку на время просчета кадра создает графика. К игровым файлам и настройкам BluePrint обращается свободно. А вот к папке Моя музыка или Windows и.т.д, BluePrint доступа не имеет. Но можно исправить при помощи плагинов. Также можно получить доступ и к базе данных через плагины.

Хотелось бы еще от себя отметить, что если вы пишите игру на С++, это не значит что нужно избегать Blueprint, наоборот, код на С++ следует писать так чтобы его потом было легко использовать на Blueprint’s как вам, так и дизайнерам. У UE4 для этого есть множество манипуляций модификаторами доступа как для переменных так и для функций (Макросы при объявлении). Так например, базовую логику основного класса, следует писать на коде C++, скрыв функции внутренней логики, которые вы считаете что не нужно видеть дизайнерам, или вам во время процесса оформления игры. Наоборот, раскрывать для доступа в блупринтах нужно те функции, которые могут реализовать или модифицировать геймплей игры. Отдельные классы, наследуемые от базового, написанного на C++ коде, следует делать на Blueprint’ах, чтобы быстро получать доступ к параметрам и функциям которые определяют геймплей игры. Я такие классы иногда называю игровые, так как они имеют непосредственное обращение с игроком на сцене, это те же предметы инвентаря, интерактивные объекты с уникальной логикой и другое. Многие их так же называют Blueprint классы.
Если грамотно написать код на С++, то у вас получатся очень опрятные и удобные Blueprint классы, которые, вы в любой момент сможете изменить, при этом не лазая по дальним уголкам кода. Следуя описанному принципу, С++ будет для вас мощным инструментом по написанию логики игры, а Blueprint’s будет таким же мощным инструментом по ее оформлению.

Blueprints Pure-functions скриптинг. Или как сделать код быстрее. Как правильно использовать Pure функции обеспечив тем самым ваш код быстродействием.

Важно запомнить, что при каждом обращении к Pure-функции вы вызываете ее снова и снова. Так например мы, казалось бы, вызвали функцию 1 раз, однако это не так — верхняя часть картинки полностью идентична нижней, так как мы 3 РАЗА просим у нее данные, записывая их в локальные переменные, по этому и функция будет вызвана 3 раза.

Из изложенного следует извлечь пару правил по работе с Pure функциями:
1. Если вы видите, что у вас в коде обращение к Pure функции происходит несколько раз, то значение выдаваемое такой функции следует записать в локальную переменную. Таким образом вы ограничите вызов Pure функции, а значение которое было записано останется таким же неизменным как и при повторном обращении к ней, так как функция выполняет свое тело в один «такт» и извлекаемое внутри нее значение из другой функции никак не может отличаться от ранее извлеченного — оно просто не успеет изменится.
2. Если, у вас сложная Pure-функция выдает 2 или более аргумента, то такую функцию не следует делать Pure функцией. Лучше оставьте ее Impure функцией и вызовите ее в Route-последовательности, тогда сколько бы раз вы не обращались к выходным аргументам этой функции, она будет вызвана только и только один раз в заданной Route-последовательности, а ее выходные аргументы можно использовать бесчисленное множество раз.
Однако, не стоит забывать что исполняющая функция может изменять извлекаемое значение посредством описанной логики, и потому в разных участках кода значение может не соответствовать необходимому. По этому нужно быть внимательным когда локальные переменные нужно перезаписать — например в функция внутри тела изменяет значение int, и вам нужно вернуть обновленное значение из функции, тогда локальное значение, записанное в начале функции, не будет соответствовать измененному.
* К сожалению на блупринтах невозможно вызвать подобные Pure функции и считать с них выходные аргументы единожды вызвав Pure-функцию.
** Отчасти, Pure-функции и делают игры написанные на Blueprints медленнее чем те что написаны на C++. Такой участок кода написанный на блупринтах является медленным по сравнению с тем что был бы записан на C++, где подобная запись.
StaticMeshComponent->GetWorldTransform(_Origin, _BoxExtent, _ExtentSphereRadius);
вызвала бы функцию GetWorldTransform только один раз, записав подаваемые поля.
*** Чтобы исключить сомнения по поводу повторного вызова Pure функции при каждом обращении к ее выходному аргументу, вы можете самостоятельно проверить это, создав свою Pure функцию в теле которой добавьте Print String. На BeginPlay() вызовите 2 события которые будут обращаться к вашей функции. Вы увидите что Print String напечатается 2 раза — это и подтвердит что функция, которая в чертежах визуально вызвана 1 раз, на самом деле вызвалась столько раз сколько раз вы к ней явно обратились.

Blueprint’ы — это разве плюс движка?
Визуальное программирование — это не программирование. Это применимо лишь в качестве стейт-машины для анимаций, простых сценарий. В добавок, они еще и бинарные, что мешает использовать git. Для более взрослой логики, эти принты становятся абсолютно нечитаемы, и нельзя применять шаблоны проектирования.
Хороший движок отличает хорошее api, расширяемость, гибкость, простота и возможность быстро сделать тулзу.

Да, блупринты — весьма себе плюс. Это вам любой дизайнер подтвердит. Визуальный «скриптинг» вполне себя зарекомендовал, и, например, часто используется для описания материалов (шейдеров), причем не только в Unreal. Часть «сложной» логики можно реализовать кодом и сделать доступной для блупринтов, так последние станут менее запутанными и более читаемыми.

В данном ключе «дизайнеры» — те, кто не пишут код, но могут менять/настраивать блупринты. Воркфлоу в анриале такой:

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

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

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

Что на счет хранения данных в UE?

Зависит от данных. Если это настройки или сохраненные игры, можно написать расширение класса SaveGame. Если нужны кастомные свойства на игровых картах — пишем свой класс WorldSettings. Достаточно все поля, требующие сохранения, отметить как UPROPERTY. Для общих данных можно использовать классы DataTable и DataAsset. Для DataTable надо будет сначала описать структуру данных (создать блупринтовую или C++ структуру), а для DataAsset — унаследовать свой класс от него. Кроме встроенного редактора таблиц, в DataTable можно импортировать данные из csv файла. Также можно просто создать структуру и объявить ее как свойство актора или компонента.

Закладка Постоянная ссылка.

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

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