Делегаты позволяют нам вызывать функцию не знаю какая именно назначена функция. Они являются безопасной версией указателя на функцию. Здесь будет разобрано как ассоциировать UFUNCTION с делегатом, чтобы она вызывалась, когда он выполняется.
Чтобы получился этот пример, необходимо использовать проект с классом TriggerVolume из прошлой статьи.
Чтобы получился этот пример, необходимо использовать проект с классом TriggerVolume из прошлой статьи.
Как это сделать...
- Внутри заголовочного файла GameMode объявить делегат с помощью специального макроса, который нужно написать над UCLASS():
DECLARE_DELEGATE(FStandardDelegateSignature) UCLASS() class EVENT_API AEventGameModeBase : public AGameModeBase
- Добавить новый член класса в GameMode:
FStandardDelegateSignature MyStandardDelegate;
- Создать в редакторе движка новый класс Actor, назвав его DelegateListener. И добавить в заголовочный файл нового класса следующие объявления:
UFUNCTION() void EnableLight(); UPROPERTY() UPointLightComponent* PointLight;
- В конструктор класса, надо добавить код для создания компоненты направленного освещения:
PointLight = CreateDefaultSubobject<UPointLightComponent>("PointLight"); RootComponent = PointLight; PointLight->SetVisibility(false);
- Внутри функции DelegateListener::BeginPlay(), добавить следующую реализацию:
const UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameModeBase* GameMode = UGameplayStatics::GetGameMode(TheWorld); AEventGameModeBase * MyGameMode = Cast<AEventGameModeBase>(GameMode); if (MyGameMode != nullptr) { MyGameMode->MyStandardDelegate.BindUObject(this, &ADelegateListener::EnableLight); } }
- Написать функцию EnableLight():
void ADelegateListener::EnableLight() { PointLight->SetVisibility(true); }
- Поместить следующий код в функцию NotifyActorBeginOverlap() класса TriggerVolume:
void AMyTriggerVolume::NotifyActorBeginOverlap(AActor * OtherActor) { const UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameModeBase* GameMode = UGameplayStatics::GetGameMode(TheWorld); AEventGameModeBase * MyGameMode = Cast<AEventGameModeBase>(GameMode); MyGameMode->MyStandardDelegate.ExecuteIfBound(); } }
- Теперь можно скомпилировать проект. Также необходимо убедиться, что для уровня установлен мой GameMode, что можно сделать в настройках мира внутри редактора движка.
После этого надо перетащить на уровень объекты классов AMyTriggerVolume и ADelegateListener.
Если запустить игру через Play, то можно будет увидеть, что когда игрок пересекает триггер, зажжется свет.
Как это работает...
- Внутри заголовочного файла GameMode устанавливается тип делегата без параметров, который называется FTriggerHitSignature. (Не знаю, опечатка это или я что-то упускаю, но не вижу ничего с таким названием.)
- Далее создается делегат как член класса GameMode.
- Добавляется компонент PointLight в класс DelegateListener, таким образом теперь у нас есть визуальное представление выполнения делегата.
- В конструкторе создается компонент UPointLightComponent.
- В переопределенном BeginPlay() получаем указатель на текущий игровой мир и используем его для получения установленного для мира GameMode через функцию GetGameMode().
- С помощью шаблонной функции Cast приводим полученный AGameMode* к моему типу AEventGameModeBase.
- После этого появляется доступ к делегату внутри GameMode, которого связываем с функцией EnableLight(). Теперь если делегат будет выполнятся, то произойдет вызов этой функции. Т.е. класс DelegateListener подписывается на сигнал от делегата из GameMode.
- В данном случае с делегатом связывается мною созданная функция UFUNCTION(), когда используется BindUObject(). Если нужно связать обычную функцию класса С++, то можно использовать BindRaw(). А в случае, если надо связать статическую функцию, то надо использовать BindStatic().
- Когда игрок пересекает объект TriggerVolume, то тот находит GameMode и запускает выполнение делегата через ExecuteIfBound().
- ExecuteIfBound() проверяет есть ли присоединенные к делегату функции и затем вызывает их.
- Функция EnableLight() включает компонент PointLight, когда вызывается делегат.
Комментарии
Отправить комментарий