Функции (Function) в Unreal Engine

Друзья, приветствую, с Вами Будуев Антон. В данной статье мы подробно поговорим о том, что такое функции в Unreal Engine (UE4, UE5) в целом и в Blueprint в частности. Обсудим их структуру, ограничения, отличие от событий и макросов, а также затронем Pure-функции.

Вскоре выйдет моя бесплатная книга по Blueprints для Unreal Engine в PDF формате. Как она выйдет, рекомендую её скачать, чтобы Вы детально изучили блюпринты Анрил Энджин.

Функции (Function) в Unreal Engine

Функции (Function) в Unreal Engine — это самостоятельные именованные блоки кода, предназначенные для выполнения конкретных задач или операций только тогда, когда их явно вызывают. Они представляют собой инструменты для организации, сегментирования и структурирования программной логики, а также позволяют повторно использовать код по мере необходимости.

Функции могут принимать входную информацию (Input, входные параметры) и возвращать информацию (Output, возвращаемые значения). Это позволяет делать код внутри функции универсальным, поскольку функция может принимать определённые параметры в качестве входных данных и возвращать результат на основе этих входных параметров, предварительно каким-либо образом переработав их.

Поскольку код внутри функции изолирован, в нём можно создать локальные переменные (Local Variables), которые существуют только внутри функции. Эти переменные создаются при вызове функции и уничтожаются при её завершении.

Функции могут быть созданы как в визуальном редакторе Blueprint, так и в коде на языке C++, что делает их универсальным решением для разработчиков с разным уровнем подготовки и предпочтениями.

В системе Blueprint функции создаются визуально с использованием графических узлов и соединений. Для создания новой функции необходимо перейти в панель My Blueprint, выбрать раздел Functions и нажать кнопку +, чтобы добавить функцию. После этого разработчик может определить входные параметры, визуальную логику и, при необходимости, возвращаемое значение. Созданная функция становится доступной для вызова из других частей графа, например, из Event Graph. Визуальная природа Blueprints позволяет легко понять и модифицировать логику функции без написания кода. Такие функции могут принимать параметры и возвращать результаты, что обеспечивает гибкость при реализации игровой механики.

При разработке на C++ функции реализуются как методы классов, унаследованных от базовых классов движка. Чтобы функция была доступна в системе Unreal (например, для вызова из Blueprints, сериализации или сетевой репликации), она должна быть помечена макросом UFUNCTION(). Этот макрос регистрирует функцию в системе рефлексии движка и позволяет управлять её поведением и доступностью с помощью спецификаторов, таких как BlueprintCallable (вызов из Blueprint), Category (группировка), а также спецификаторов для сетевой репликации (Server, Client, NetMulticast) и других. Функции на C++ обеспечивают высокую производительность, строгую типизацию и доступ к низкоуровневым возможностям движка.

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

Функции в Blueprint

Функции в Blueprint представляют собой визуальные блоки логики, создаваемые с помощью графического интерфейса редактора Unreal Engine. Каждая функция существует как отдельный граф, содержащий последовательность узлов, соединённых между собой для выполнения определённой задачи.

Функции (Blueprint Function) в Unreal Engine (UE4, UE5)
Функции (Blueprint Function) в Unreal Engine (UE4, UE5)

Создание и настройка

Процесс создания функции начинается с открытия Blueprint-класса. В панели My Blueprint находится раздел Functions, где можно добавить новую функцию с помощью кнопки +. После создания функции ей присваивается имя, которое рекомендуется изменить на осмысленное, отражающее её назначение.

Создание функции в Unreal Engine
Создание функции в Unreal Engine

Через панель свойств Details можно добавить входные параметры (Inputs) и, при необходимости, выходные параметры (Output). Каждый параметр имеет строгий тип данных — целое число, число с плавающей точкой, строка, булево значение, ссылка на объект, массив, структура и т.д. Параметрам можно задавать значения по умолчанию, которые будут использоваться, если при вызове значение не передано.

Добавление входящих (Inputs) и исходящих (Outputs) параметров
Добавление входящих (Inputs) и исходящих (Outputs) параметров

Структура функции

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

Входной узел выполнения
Входной узел выполнения

В отличие от событий, функции не могут содержать заторможенные (Latent) узлы, такие как Delay или Async Load, поскольку выполняются синхронно в рамках одного кадра. Это делает их подходящими для быстрых операций, не требующих ожидания.

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

Return Node (узел возврата)
Return Node (узел возврата)

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

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

Функции могут содержать несколько узлов Return (например, в разных ветках Branch)
Функции могут содержать несколько узлов Return (например, в разных ветках Branch)

Работа с параметрами

Параметры в Blueprint-функциях позволяют передавать данные внутрь функции и возвращать результаты её работы. Они играют ключевую роль в создании гибких и переиспользуемых блоков логики. Параметры делятся на 2 основных типа:

  • Input (входные параметры) — передаются в функцию при вызове.
  • Output (выходные параметры) — позволяют функции возвращать результаты своей работы вызывающему эту функцию коду.

Сами параметры задаются внутри функции во вкладке Details в разделах Inputs и Outputs. Чтобы добавить параметр, необходимо нажать на + рядом с Inputs или Outputs, ввести имя параметра и установить тип данных (Float, Integer, Boolean и т.д.). В целом, разработчик может определить любое количество параметров каждого типа.

Добавление входящих (Inputs) и исходящих (Outputs) параметров
Добавление входящих (Inputs) и исходящих (Outputs) параметров

Вызов функций

Вызов функции осуществляется через специальный узел, который создаётся в Event Graph или внутри другой функции. Обычно это делается через контекстное меню (ПКМ / поиск по имени функции) или при перетаскивании функции из панели My Blueprint в область Event Graph. При создании узел автоматически получает все соответствующие пины для параметров.

Узел вызова функции
Узел вызова функции

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

Функции могут вызываться из различных контекстов: из Event Graph или других функций, а также из других Blueprints при наличии ссылки на Актор.

Настройки функций (вкладка Details)

Настройки функций (вкладка Details)
Настройки функций (вкладка Details)
  • Description — позволяет добавить подробное текстовое описание предназначения и работы функции. Это описание отображается в подсказках при наведении курсора на узел функции в редакторе Blueprint. Хорошо написанное описание помогает другим разработчикам понимать назначение функции без необходимости изучения ее внутренней логики. Описание может содержать информацию о параметрах, возвращаемых значениях и примерах использования функции.
  • Category — определяет, в какой категории функций будет отображаться текущая функция при поиске и выборе. Это позволяет организовать функции по логическим группам, таким как «Math», «Utilities», «Gameplay» или любым другим пользовательским категориям. Правильная категоризация упрощает поиск нужных функций и делает интерфейс редактора более структурированным. Также категории могут быть вложенными.
  • Keywords — позволяет задать дополнительные ключевые слова, по которым функция будет находиться при поиске. Это особенно полезно для функций, которые могут быть найдены по разным терминам или синонимам. Ключевые слова разделяются запятыми и могут включать сокращения, альтернативные названия или термины, связанные с функциональностью функции.
  • Compact Node Title — позволяет задать краткое название для отображения на узле функции в графе Blueprint. Это полезно для функций с длинными именами, которые могут занимать много места на схеме. Компактное название отображается на самом узле, в то время как полное имя функции сохраняется для использования в поиске и документации. Это помогает сделать графы функций более читаемыми и компактными.
  • Pure — указывает, что функция является чистой, то есть не изменяет состояние объектов. Чистые функции не имеют Execution-пинов и вызываются без последовательности выполнения напрямую при запросе возвращаемых данных. Они автоматически обновляют свои выходные значения при изменении входных параметров. Чистые функции должны содержать только логику вычислений и не могут включать узлы, изменяющие состояние.
  • Call In Editor — позволяет вызывать функцию непосредственно из редактора Unreal Engine, не запуская игру. Это полезно для функций, которые выполняют вспомогательные операции, такие как настройка объектов, генерация контента или отладочные действия. Функция становится доступна в контекстном меню объекта в редакторе и может быть вызвана во время разработки для выполнения различных задач подготовки сцены.
  • Access Specifier — определяет уровень доступа к функции из других Blueprint-классов. Этот параметр позволяет контролировать инкапсуляцию функций и предотвращать их несанкционированное использование из других частей проекта. Правильная настройка уровня доступа важна для поддержания чистой архитектуры проекта. Доступны следующие уровни:
    • Public — доступна всем,
    • Protected — доступна только наследникам,
    • Private — доступна только внутри текущего класса.
  • Const — указывает, что функция не изменяет состояние объекта, на котором она вызывается. Такие функции могут быть вызваны на константных объектах и гарантируют отсутствие побочных эффектов. Этот параметр важен при работе с C++ функциями, которые объявлены как константные методы. Const функции обеспечивают дополнительную безопасность и предсказуемость в поведении кода.
  • Exec — позволяет функции обрабатывать консольные команды, вводимые в редакторе или во время выполнения игры. Когда функция помечена данным флагом, она становится доступной для вызова через консоль разработчика, что представляет собой мощный инструмент для отладки, тестирования и управления игровым процессом в реальном времени.
  • Thread Safe — указывает, что функция может быть безопасно вызвана из разных потоков выполнения. Это важно для функций, которые могут использоваться в многопоточных операциях, таких как асинхронная загрузка данных или фоновые вычисления. Пометка функции как потокобезопасной позволяет движку корректно обрабатывать ее вызовы в параллельных контекстах без риска возникновения гонок данных или других проблем синхронизации.
  • Unsafe During Actor Construction — указывает, что функция может быть небезопасной при вызове во время конструирования Актора. Такие функции могут вызывать проблемы при использовании в Construction Script или во время создания объектов в редакторе. Отметка этого флага предупреждает разработчиков о потенциальных проблемах и помогает избежать ошибок, связанных с преждевременным вызовом функций до полной инициализации объекта.
  • Deprecated — помечает функцию как устаревшую и не рекомендуемую для использования. Это позволяет постепенно выводить из употребления старые функции, сохраняя обратную совместимость. При использовании устаревших функций редактор будет отображать предупреждения, уведомляя разработчиков о необходимости замены на более новые альтернативы.
  • Deprecation Message — позволяет задать текстовое сообщение, которое будет отображаться при использовании устаревшей функции. Сообщение может содержать информацию о причинах устаревания функции и рекомендации по использованию альтернативных решений. Хорошо составленное сообщение помогает разработчикам быстро понять, как заменить устаревшую функцию на более современную реализацию.
  • Inputs — позволяет настраивать входные параметры функции. Здесь можно добавлять, удалять и модифицировать параметры, определяя их имена, типы данных и значения по умолчанию.
    • Default Value — позволяет задать значение по умолчанию для входного параметра функции, которое будет использоваться, если при вызове функции соответствующее значение не будет передано явно.
    • Pass-by-Reference — определяет способ передачи параметра в функцию. Когда этот флаг активен, параметр передается по ссылке, что означает, что функция работает с оригинальным объектом или значением, а не с его копией. Это позволяет функции изменять содержимое сложных типов данных, таких как массивы или структуры, и эти изменения будут видны вне функции. При передаче по ссылке не происходит создания копии данных, что может улучшить производительность при работе с большими объемами информации. Однако это также требует осторожности, поскольку изменения внутри функции могут повлиять на исходные данные. Когда флаг не активен, параметр передается по значению, и функция работает с копией данных, что обеспечивает безопасность исходных значений, но может потреблять больше памяти для сложных типов данных.
  • Outputs — позволяет настраивать выходные (возвращаемые) параметры функции. Здесь определяются значения, которые функция будет возвращать после выполнения. Выходные параметры могут иметь различные типы данных и могут включать как простые значения, так и сложные структуры данных.

Pure функции

Pure функции в Unreal Engine (Blueprint)
Pure функции в Unreal Engine (Blueprint)

Pure (чистые) функции в Blueprint представляют собой специальный тип функций, которые не изменяют состояние объекта или игрового мира. Они предназначены исключительно для выполнения вычислений и возвращения результатов на основе переданных входных параметров. Их поведение полностью определяется входными данными, и при одинаковых значениях на входе они всегда возвращают одинаковый результат. Это делает их детерминированными, предсказуемыми и безопасными для использования в любом контексте без риска нарушить логику игры.

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

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

Не-Pure функции, напротив, могут выполнять действия, изменяющие состояние системы. Они включают в себя операции вроде изменения переменных, перемещения объектов, воспроизведения звуков, спавна Акторов или вызова событий. Такие функции требуют явного вызова через последовательность выполнения и обозначаются синей иконкой в редакторе. Они подходят для реализации активной игровой логики, где необходимо повлиять на объекты или мир в процессе выполнения.

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

Чтобы пометить функцию как Pure, необходимо открыть панель Details в редакторе Blueprint и установить соответствующую опцию Pure.

Опция Pure во вкладке Details
Опция Pure во вкладке Details

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

Blueprint функции и Time-узлы

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

Особенность Time-узлов заключается в их асинхронной природе. В отличие от стандартных узлов, которые выполняются мгновенно, асинхронные узлы требуют сохранения контекста выполнения между кадрами. Например, узел Delay приостанавливает поток выполнения на заданное количество секунд, а Timeline постепенно изменяет выходные значения в течение определённого промежутка времени. Для корректной работы такие узлы полагаются на систему событий, способную «приостанавливать» и «возобновлять» выполнение.

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

Для работы с Time-узлами необходимо использовать графы, поддерживающие асинхронное выполнение, прежде всего — Event Graph. В нём можно использовать Delay, Custom Events, Timers, Timeline и другие механизмы, которые позволяют корректно управлять временными операциями. Именно в Event Graph движок может «запомнить» точку ожидания и возобновить выполнение позже, что делает его единственным подходящим местом для использования асинхронных узлов в большинстве случаев.

Локальные и глобальные переменные

Локальные переменные (Local Variables) в Blueprint-функциях представляют собой переменные, которые создаются и используются исключительно в пределах графа конкретной функции. Они объявляются непосредственно внутри функции и недоступны за её пределами.

Локальные переменные (Local Variables)
Локальные переменные (Local Variables)

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

При создании локальной переменной разработчик определяет её тип данных, имя и, при необходимости, начальное значение. Поддерживаются все стандартные и пользовательские типы данных Unreal Engine: целые и вещественные числа, булевы значения, строки, векторы, ротаторы, ссылки на объекты, массивы, структуры и другие. Локальные переменные удобны для выполнения временных операций, таких как расчёты, проверки условий или обработка данных в рамках одного вызова функции. Поскольку их состояние не сохраняется, каждый новый вызов функции начинается с чистого значения, что обеспечивает предсказуемость и изолированность.

Глобальные переменные или, иначе говоря, переменные уровня Blueprint-класса — это переменные, объявленные в основном графе Blueprint, в разделе My Blueprint / Variables.

Переменные уровня Blueprint-класса
Переменные уровня Blueprint-класса

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

Функции могут как читать, так и изменять переменные уровня Blueprint-класса, если те не защищены настройками доступа. Изменение таких переменных влияет на общее состояние объекта и может повлиять на поведение других функций, событий или систем. Это требует особой осторожности: непродуманное изменение переменной может привести к трудноуловимым ошибкам или неожиданному поведению. Например, изменение счётчика Ammo в одной функции может повлиять на логику перезарядки в другой.

Важным аспектом при работе с переменными является понимание их области видимости и времени жизни.

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

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

Blueprint Function Library

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

Создание библиотеки функций осуществляется в редакторе Unreal Engine через создание нового Blueprint-класса Blueprint Function Library. Для этого в Content Browser через контекстное меню ПКМ выбирается пункт BlueprintBlueprint Function Library.

Создание Blueprint Function Library
Создание Blueprint Function Library

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

Функции, созданные в библиотеке, автоматически появляются в контекстном меню (ПКМ) при работе с любым Blueprint. Разработчик может организовать функции по тематическим группам, используя категории, что упрощает поиск и использование нужных инструментов. Это особенно полезно в крупных проектах, где множество разработчиков использует единые стандарты и методы.

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

Отличие функций от макросов и событий

В Unreal Engine в системе Blueprint функции (Function), макросы (Macros) и события (Events) — это три разных механизма визуального программирования, каждый из которых выполняет свою роль в построении логики игры. Несмотря на внешнее сходство, они принципиально отличаются по назначению, поведению и способу использования.

Отличие функций от макросов и событий
Отличие функций от макросов и событий

Функции в Blueprint представляют собой переиспользуемые блоки синхронной логики, предназначенные для выполнения конкретных задач. Они вызываются явно и выполняются полностью в рамках одного кадра. Функции могут принимать параметры, возвращать значения и использоваться многократно как внутри одного Blueprint, так и из других. Они идеально подходят для организации повторяющейся логики, например, расчёта урона, проверки условий или изменения состояния объекта. Функции не могут содержать асинхронные узлы, такие как Delay, поскольку их выполнение должно завершиться мгновенно. Они создаются в разделе My Blueprint / Functions и могут быть помечены как Pure, если не изменяют состояние и возвращают только вычисленное значение.

События (Events), в отличие от функций, представляют собой реакции на определённые действия или изменения в игре. Они срабатывают автоматически при наступлении определённого условия: начале игры (Begin Play), столкновении объектов (On Component Begin Overlap), нажатии кнопки (Input Action). События не вызываются вручную — они активируются движком в нужный момент. Каждое событие имеет своё имя и, как правило, связано с конкретным объектом или системой. В отличие от функций, события могут содержать асинхронные узлы и работать с задержками, так как их выполнение управляется движком и может растягиваться во времени. События находятся в Event Graph и служат точками входа для логики, реагирующей на внешние или внутренние триггеры.

Макросы (Macros) — это особый тип визуальных блоков, которые работают как текстовые подстановки на этапе компиляции графа. В отличие от функций, макросы не являются отдельными программными сущностями. Вместо этого, каждый раз, когда макрос используется в графе, его содержимое копируется напрямую в место вызова. Это означает, что макросы не создают отдельного контекста выполнения и не могут быть отлажены как отдельные блоки. Они полезны для сокращения повторяющихся цепочек узлов, например, для стандартной проверки валидности ссылки на объект или для часто используемой комбинации математических операций. Однако, поскольку макросы раскрываются в графе, они не подходят для сложной логики, требующей параметров с передачей по ссылке или возврата значений, как функции. Макросы создаются в редакторе отдельно и доступны через контекстное меню.

Ключевое отличие между этими тремя элементами заключается в их архитектуре и цикле жизни.

Функции — это вызываемые синхронные блоки, события — автоматически срабатывающие триггеры, а макросы — статические вставки кода.

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

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

Правила хорошего тона при использовании пользовательских Blueprint функций в Unreal Engine

  1. Всё, что повторяется дважды — выносим в функцию: даже если дублирование кажется незначительным, при втором появлении логики уже стоит задуматься о выносе в отдельную функцию для поддержки принципа DRY (Don’t Repeat Yourself).
  2. Сложную логику разбиваем на подфункции: если функция становится громоздкой или содержит вложенные ветвления, разбейте её на более мелкие, понятные части — это улучшает читаемость и тестируемость.
  3. Ограниченная ответственность: каждая функция должна решать одну конкретную задачу, а не объединять в себе несколько логически разных операций.
  4. Семантически правильные имена: называйте функции так, чтобы их назначение было понятно с первого взгляда, используя глаголы и избегая неочевидных сокращений (например, CalculateDamage).
  5. Использование Pure-функций: если функция не изменяет состояние объектов, а только возвращает результат вычислений, создавайте эту функцию чистой (Pure).
  6. Чёткие и минимальные входные параметры: передавайте в функцию только необходимые данные, избегая избыточных параметров или полных объектов при необходимости лишь одного значения.
  7. Использование возвращаемых значений: возвращайте результат вычислений через выходные параметры, а не записывайте его во внешние переменные напрямую.
  8. Документирование через комментарии: добавляйте описания в поле Description и используйте визуальные комментарии в графе для пояснения сложной логики.
  9. Асинхронные операции: асинхронные узлы (Delay, Async Load Asset и прочее) внутри обычных Blueprint-функций не работают. Для таких операций применяйте Blueprint-события или макросы.
  10. Организация и структура: группируйте связанные функции в одном Blueprint, используя категории.
  11. Тестирование и отладка: проверяйте работу функции в разных контекстах, используя точки останова и временные отладочные узлы.
  12. Производительность: избегайте тяжёлых операций в функциях, вызываемых часто, и не используйте их в Event Tick без необходимости.
  13. Валидация входных данных: проверяйте ссылки на объекты на валидность, особенно если функция может вызываться из разных источников.
  14. Не злоупотребляйте глобальными функциями: размещайте в Blueprint Function Library только действительно универсальные и независимые функции.
  15. Следите за зависимостями: избегайте циклических ссылок между Blueprint и не создавайте взаимных вызовов функций по кругу.

Пример использования пользовательских функций

Рассмотрим пример применения пользовательских функций на примере двух шаблонов проектов игр от третьего лица в движке Unreal Engine: один из версии UE 5.4, другой — из UE 5.6.

Шаблон из UE 5.4

Откроем Blueprint-класс персонажа BP_ThirdPersonCharacter, расположенный по пути /All/Game/ThirdPerson/Blueprints, и изучим логику настройки поворота камеры.

Логика настройки поворота камеры в BP_ThirdPersonCharacter UE 5.4
Логика настройки поворота камеры в BP_ThirdPersonCharacter UE 5.4

Поскольку камера по умолчанию привязана к контроллеру, её вращение полностью зависит от поворота контроллера. В данной логике происходит именно управление поворотом контроллера. Событие Enhanced Input Action IA_Look обрабатывает движение мыши (а также геймпад) и передаёт значения смещения по осям X и Y на оси поворота контроллера с помощью встроенных функций Add Controller Yaw Input и Add Controller Pitch Input.

Шаблон из UE 5.6

Аналогично откроем Blueprint-класс персонажа BP_ThirdPersonCharacter и рассмотрим логику настройки поворота камеры здесь. В этой версии подход немного отличается.

Логика настройки поворота камеры в BP_ThirdPersonCharacter UE 5.6
Логика настройки поворота камеры в BP_ThirdPersonCharacter UE 5.6

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

  • События геймпада — Enhanced Input Action IA_Look;
  • События сенсорного интерфейса — Event Secondary Thumbstick;
  • События движения мыши — Enhanced Input Action IA_MouseLook.

Каждое из этих событий приходит с уникального устройства, но на выходе все они возвращают одинаковый набор данных — изменения по осям X и Y. Для корректной работы их необходимо передать на поворот контроллера.

Вместо того, чтобы дублировать одинаковый код в каждом из трех случаев, разработчики выделили общую логику в отдельную пользовательскую функцию Aim. В этой функции, как и в случае с логикой из шаблона в UE 5.4, реализована обработка значений поворота через встроенные функции Add Controller Yaw Input и Add Controller Pitch Input. Таким образом, события просто вызывают эту функцию с соответствующими параметрами, что существенно упрощает поддержку и развитие кода.

Логика функции Aim в BP_ThirdPersonCharacter UE 5.6
Логика функции Aim в BP_ThirdPersonCharacter UE 5.6

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

Обзор основных встроенных Blueprint функций Unreal Engine

Теперь, когда мы разобрали, как создавать и использовать пользовательские функции в Blueprint, перейдём к обзору встроенных, готовых функций, которые Unreal Engine предоставляет разработчику из коробки для решения типичных задач.

Поскольку встроенных функций в движке огромное количество, ниже приведены ссылки на отдельные статьи с обзором функций для каждого основного Blueprint-класса в Unreal Engine — это поможет быстро найти нужную функцию и понять её назначение.

Совет. Вскоре выйдет моя бесплатная книга по Blueprints для Unreal Engine в PDF формате. Как она выйдет, рекомендую её скачать, чтобы Вы детально изучили блюпринты Анрил Энджин.


наш Телеграм канал

Оцените статью
( 1 оценка, среднее 5 из 5 )
Поделитесь этой статьей со своими знакомыми в социальных сетях, возможно, эта статья кому-то будет полезна
Unreal Engine - это просто
Добавить комментарий

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