Функции, макросы и переиспользование логики

Урок про то, как не дублировать логику в Blueprint: функции, макросы и их различия.

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

Зачем выносить логику в функции

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

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

Функция создаётся в панели My Blueprint кнопкой плюс рядом с Functions. У неё есть нода входа (с параметрами) и, при необходимости, нода Return (с результатом). Параметры и возвращаемые значения настраиваются в Details функции.

Функция: CalculateDamage(Base, Multiplier) -> Float
[Вход: Base, Multiplier] --> [Multiply] --> [Return: результат]

Вызов в графе:
[CalculateDamage  Base=10  Multiplier=2] --(Float=20)--> [Apply]

Функция против макроса

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

СвойствоФункцияМакрос
Несколько выходов потокаНет (один поток)Да (можно ветвить)
Может содержать задержку (Delay)НетДа
Своя нода на графеДа, чистый вызовПодставляется как «копипаста»
Переиспользование между блюпринтамиЛегко (в т.ч. через интерфейсы)Через Macro Library

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

Чистые функции (Pure)

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

Как работает под капотом

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

Частые ошибки

  • Ставить Delay в функцию. Функции не поддерживают задержки — для этого нужен макрос или сам граф события.
  • Делать Pure-функцию с побочными эффектами. Pure может вызываться неожиданно много раз; в ней нельзя менять состояние.
  • Дублировать логику вместо функции. Это создаёт ад при поддержке.

Интерфейсы Blueprint

Когда логику нужно вызвать у объекта, точный класс которого вы не знаете, на помощь приходят Blueprint Interface. Интерфейс — это набор объявленных функций без тела, своего рода контракт: «любой, кто реализует этот интерфейс, умеет такие действия». Например, интерфейс Interactable с функцией Interact могут реализовать дверь, сундук и рычаг по-своему. Игрок, нажав «использовать», просто вызывает Interact у того, на что смотрит, не зная и не заботясь, что это конкретно за объект.

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

Итоги

  • Функция выносит повторяющуюся логику в один вызов с параметрами и результатом.
  • Макрос отличается: поддерживает несколько выходов потока и задержки, но инлайнится.
  • Pure-функции без пинов потока хороши для геттеров и расчётов.
  • Функции компилируются в подпрограммы, макросы разворачиваются в месте вызова.
Проверьте себя
1. Чем макрос принципиально отличается от функции?
AМакрос нельзя вызвать
BМакрос поддерживает несколько выходов потока и задержки
CМакрос всегда быстрее
DФункция не принимает параметры
2. Что характерно для Pure-функции?
AУ неё нет белых пинов потока, она только возвращает значение
BОна обязательно меняет состояние
CЕё нельзя вызвать дважды
DОна поддерживает Delay
3. Почему в обычную функцию нельзя поставить ноду Delay?
AЭто баг движка
BФункции не поддерживают задержки, для этого нужен макрос или граф события
CDelay слишком медленный
DФункции выполняются мгновенно по определению