Друзья, приветствую, с Вами Будуев Антон. В данной статье мы поговорим о том, что такое Cast (каст, приведение типов) в Unreal Engine (UE4, UE5), и в частности в Blueprint. Разберём особенности каста и как он работает «под капотом» внутри.
Вскоре выйдет моя бесплатная книга по Blueprints для Unreal Engine в PDF формате. Как она выйдет, рекомендую её скачать, чтобы Вы детально изучили блюпринты Анрил Энджин.
Cast в Unreal Engine
Cast (каст, приведение типов) в Unreal Engine — операция приведения базового типа объекта к более конкретному целевому типу. Cast проверяет, является ли объект экземпляром целевого класса или одного из его потомков. Если проверка успешна, возвращается ссылка типа целевого класса, если объект ему соответствует.

Эта операция необходима, когда объект представлен в виде базового типа (например, как Actor, Pawn, Character), но требуется доступ к специфичным свойствам/функциям целевого дочернего класса (например, BP_Enemy). Без каста движок не распознает уникальные возможности дочернего класса.
Например, при столкновении компонентов движок сообщает о другом Акторе (возвращает ссылку на общий тип Actor), но не уточняет, кто он — враг (BP_Enemy), игрок (BP_Player) или декорация. В таких случаях возникает необходимость определить, можно ли с этим объектом взаимодействовать особым образом, например, нанести урон или вызвать специальную анимацию.

Для этого выполняется попытка привести объект к конкретному классу, например, к BP_Enemy или BP_Player. Если объект действительно принадлежит этому классу, преобразование проходит успешно, и появляется возможность использовать его внутренние переменные и функции. Это делает логику поведения более точной и адаптированной к контексту.
Важно: Каст не изменяет объект — он лишь предоставляет доступ к специфичной функциональности, если объект соответствует целевому типу.
Cast To в Blueprint
В Blueprint Cast реализуется через специальный узел Cast To [Класс], который имеет два выхода: Cast Success и Cast Failed.
Эти выходы позволяют задать разное поведение в зависимости от результата приведения типа. Выход Cast Success активируется при успешном приведении, а Cast Failed — при неудаче.

Узел Cast To [Класс] принимает на вход объект и пытается преобразовать его к указанному целевому типу. Если преобразование проходит успешно, срабатывает выход Cast Success, а также возвращается действительная ссылка на объект нужного типа As [Класс]. В противном случае — срабатывает выход Cast Failed, что означает неудачу операции, а ссылка As [Класс] возвращает Null (пустую ссылку).
Это делает систему гибкой и позволяет избежать ошибок во время выполнения, связанных с попыткой доступа к несуществующим свойствам или методам.
Типичные ситуации использования
Одним из распространённых случаев является получение персонажа игрока через функцию Get Player Character. Эта функция возвращает объект общего типа Character, но чтобы использовать переменные здоровья или способности, определённые в пользовательском классе персонажа, нужно привести его к конкретному классу персонажа, созданному в проекте, например, BP_Player. Только после этого становится доступна работа с пользовательскими полями и функциями.

Ещё один пример — обработка пересечений. Когда игровой персонаж пересекается с другим объектом, событие пересечения (Event Actor Begin Overlap) возвращает его как общий Actor.
Но если при пересечении требуется взаимодействовать только с определёнными типами, а не с общим типом Actor, например, с объектами, представляющими собой поднимаемые предметы, необходимо выполнить Cast к классу BP_Pickup. Тогда успешное приведение позволяет вызвать метод сбора предмета или изменить состояние игрока.

Особенности и ограничения
- Cast работает только в рамках иерархии наследования. Это означает, что можно привести объект от базового класса (например, Actor) к его конкретному потомку (например, BP_Enemy), если он действительно является экземпляром этого класса. Прямое приведение между независимыми потомками одного предка (например, от BP_Camera к BP_Weapon) невозможно, даже если оба класса наследуются от Actor.

- Cast поддерживает проверку реализации интерфейсов. Например, узел Cast To [Interface] проверяет, реализует ли объект указанный интерфейс, и если да — предоставляет доступ к его функциям. Эта операция работает независимо от иерархии наследования: объекты разных классов, не связанные общим предком, могут успешно приводиться к одному и тому же интерфейсу, если они его реализуют. Если объект действительно реализует интерфейс, приведение завершается успешно, и появляется возможность вызывать его методы. В противном случае, если интерфейс не реализован, операция возвращает Null, а в Blueprint активируется ветка Cast Failed.

- Cast позволяет приводить ссылку на интерфейс обратно к конкретному типу объекта, реализующего этот интерфейс. Это означает, что если имеется ссылка на интерфейс (например, IInteractable), можно выполнить Cast к конкретному классу, такому как BP_Enemy или BP_Pickup, если они реализуют этот интерфейс. Движок сначала получит настоящий объект, реализующий этот интерфейс, а затем проверит, соответствует ли он указанному классу. Это расширяет гибкость системы, позволяя переходить от абстрактного поведения (интерфейс) к конкретной реализации (объект) и получать доступ к его уникальным свойствам и функциям.
На скриншоте ниже показан пример Blueprint-скрипта, который, хотя и не является оптимальным по организации логики, но наглядно демонстрирует одну из ключевых возможностей Cast — приведение ссылки на интерфейс к конкретному типу объекта, реализующему этот интерфейс.

В данном случае, при событии пересечения коллизии (Event Overlap), возвращается ссылка на объект типа Actor. Далее через Cast проверяется, реализует ли этот объект интерфейс BPI_Interact. Если да, то возвращается ссылка на интерфейс BPI_Interact. После этого эта ссылка приводится через Cast к конкретному классу BP_Camera. Если объект действительно является экземпляром BP_Camera и реализует интерфейс, то возвращается ссылка на этот конкретный объект.
Таким образом, начиная со ссылки на общий Actor, происходит поэтапное приведение сначала к интерфейсу, а затем к конкретному классу BP_Camera, реализующему этот интерфейс. Этот процесс демонстрирует, как можно из абстрактной ссылки получить доступ к уникальным свойствам и методам конкретного объекта.
- Cast не изменяет сам объект — он лишь предоставляет возможность обращаться к нему как к экземпляру другого класса. Сам объект остаётся неизменным, и если он не является экземпляром целевого класса, приведение завершится неудачей. Операция не создаёт копию и не влияет на состояние объекта.
- Операция приведения типа выполняется динамически, то есть во время игры, и требует вычислительных ресурсов. Хотя затраты на один Cast минимальны, множественные и неоправданные преобразования в циклах или на часто вызываемых событиях могут повлиять на производительность. Например, повторное использование Cast в событиях, вызываемых каждый кадр (Event Tick), не рекомендуется, так как это может накапливать нагрузку. Желательно выполнять приведение один раз, при возникновении события (например, при столкновении или старте игры), и сохранять ссылку в переменной через Promote to Variable (при щелчке ЛКМ по ссылке As [Класс]) для многократного обращения к этому конкретному объекту.

- Переменную, которая в Cast To была создана через Promote to Variable, необходимо проверять на валидность функцией Is Valid, чтобы избежать обращения к недействительной ссылке. Если объект был уничтожен — например, враг убит или Актор удалён из сцены — ссылка становится Null, и попытка доступа к его свойствам или функциям приведёт к ошибке.

Как Cast To работает внутри
Рассмотрим упрощенную схему работы Cast в Unreal Engine.
Когда в Blueprint используется Cast To [Целевой тип] к какой-то ссылке (например, к Other Actor из события Event Actor Begin Overlap), Unreal Engine выполняет проверку: «Можно ли переданный по ссылке объект рассматривать как объект другого, более конкретного целевого типа?».
Процесс начинается с простой проверки: если ссылка на переданный объект (например, Other Actor) пустая (Null), то привести её невозможно, и каст сразу возвращает Null, а также направляет поток выполнения через выход Cast Failed.
Если ссылка есть, движок смотрит, является ли сам переданный объект ссылкой на интерфейс (Interface). Если да, он сначала получает настоящий UObject, от которого этот интерфейс реализован, и далее продолжает проверки уже с этим объектом, пытаясь привести его к целевому типу. Если переданный объект не интерфейс, а обычный объект (UObject), то эта операция пропускается.
Далее движок анализирует сам целевой тип. Если целевой тип имеет присвоенный ему специальный флаг приведения (например, UFunction или FProperty), движок проверяет, принадлежит ли исходный объект к категории, обозначенной этим флагом, с помощью HasAnyCastFlag. Это позволяет выполнять быстрое приведение без рекурсивной проверки иерархии классов и используется для внутренних типов движка.
Если целевой тип — обычный UObject, движок сначала проверяет, не является ли он базовым классом для переданного объекта (например, приведение BP_Player к Character). В таком случае приведение происходит мгновенно, без дополнительных проверок во время выполнения.
Если прямое наследование невозможно, движок переходит к основной и наиболее распространённой проверке: он использует метаинформацию UClass объекта и вызывает внутренний метод IsA<To>(), который рекурсивно проверяет иерархию классов, чтобы убедиться, что объект действительно является экземпляром целевого типа или его потомка. Если целевой тип является интерфейсом (например, IInteractable), движок вместо этого использует GetInterfaceAddress для проверки реализации интерфейса.
В итоге, если всё в порядке, Cast возвращает ссылку на объект нужного типа, а также направляет поток выполнения на выход Cast Success, и вы можете использовать его переменные и функции. Если нет — возвращает Null и поток выполнения направляется на выход Cast Failed.
Таким образом, Cast в Unreal Engine и в Blueprint, в частности, — это оптимизированная для разных сценариев многоуровневая система проверок:
- Проверка переданной ссылки на Null.
- Работа с интерфейсами: если переданная ссылка является интерфейсом, сначала получается реализующий его UObject.
- Быстрое приведение по флагам (Cast Flags): используется для специальных типов движка, таких как UFunction или FProperty, для максимальной производительности.
- Прямое приведение по наследованию: применяется, когда целевой тип является базовым классом исходного.
- Динамическая проверка через IsA или GetInterfaceAddress: основной механизм для приведения между обычными UObject и интерфейсами.
Совет. Вскоре выйдет моя бесплатная книга по Blueprints для Unreal Engine в PDF формате. Как она выйдет, рекомендую её скачать, чтобы Вы детально изучили блюпринты Анрил Энджин.