[Unreal]#21_Custom Delegate
Unreal 개발 중 "Custom Delegate"에 대해 알아보겠습니다.
커스텀 대리자 함수 시그니처 생성 방법에 대해 살펴보겠습니다.
Custom Delegate Signature
1. 코드
DECLARE_DELEGATE(DELEGATE_NAME); //void __(void)
DECLARE_DELEGATE_RetVal_OneParam(DELEGATE_RETURN_TYPE, DELEGATE_NAME, PARAM_1_RETURN_TYPE);
Delegate
1. 기본 구조
// Delegate 활용 기본 구조
<Class 1>
L1. DECLARE_DELEGATE : Custom Delegate Signature 메크로 생성
L2. Custom Delegate 선언
-------------- 어느 클래스라도 호출이 가능한 부분
L3. IsBound() : Custom Delegate와 Binding된 함수가 존재하는지 체크
L4. Execute() : Custom Delegate와 Binding된 함수에게 인자들을 넘겨주고, 함수 대리자 실행
************************************************************************************************
<Class 2>
L1. CustomDeleagte와 Signature가 같은 사용자 정의 함수생성
L2. CustomDelegate.BindFunction or AddUFunction 을 통해 Binding을 수행합니다.
* Custom Deleagte 선언 클래스 혹은 Delegate의 바인딩을 수행하는 클래스에서 IsBound 체크 및 실행
* Custom Delegate를 반는 측에서 동일한 Delegate Signature를 갖는 함수 생성 및 Binding 수행
코드 예제
1. ActorBeginOverlap.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C01_ActorBeginOverlap.generated.h"
UCLASS()
class U03_CPP_API AC01_ActorBeginOverlap : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Scene;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC01_ActorBeginOverlap();
protected:
virtual void BeginPlay() override;
private:
// FActorBeginOverlapSignature
UFUNCTION()
void ActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
// FActorEndOverlapSignature
UFUNCTION()
void ActorEndOverlap(AActor* OverlappedActor, AActor* OtherActor);
};
- 대리자 함수와 바인딩되는 함수는 같은 함수 시그니처를 가져야합니다!
- FActorBeginOverlapSignature(제공 시그니처)와 동일한 함수 시그니처를 갖는 ActorBeginOverlap 생성
- FActorEndOverlapSignature(제공 시그니처)와 동일한 함수 시그니처를 갖는 ActorEndOverlap 생성
2. ActorBeginOverlap.cpp
#include "C01_ActorBeginOverlap.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/SceneComponent.h"
#include "Components/TextRenderComponent.h"
AC01_ActorBeginOverlap::AC01_ActorBeginOverlap()
{
CHelpers::CreateComponent<USceneComponent>(this, &Scene, "Scene");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Scene);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Scene);
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName());
}
void AC01_ActorBeginOverlap::BeginPlay()
{
Super::BeginPlay();
// OnActorBeginOverlap 대리자 함수는 함수 포인터를 활용해 ActorBeginOverlap을 호출
OnActorBeginOverlap.AddDynamic(this, &AC01_ActorBeginOverlap::ActorBeginOverlap);
OnActorEndOverlap.AddDynamic(this, &AC01_ActorBeginOverlap::ActorEndOverlap);
}
void AC01_ActorBeginOverlap::ActorBeginOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
FString str = "";
str.Append("C++ Actor Begin Overlap : ");
str.Append(OtherActor->GetName());
CLog::Log(str);
}
void AC01_ActorBeginOverlap::ActorEndOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
FString str = "";
str.Append("C++ Actor End Overlap : ");
str.Append(OtherActor->GetName());
CLog::Log(str);
}
커스텀 대리자 함수 활용 방법
1. Trigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C03_Trigger.generated.h"
DECLARE_DELEGATE(FBoxLightBeginOverlap); //void __(void)
DECLARE_DELEGATE(FBoxLightEndOverlap); //void __(void)
DECLARE_DELEGATE_RetVal_OneParam(FString, FBoxLightRandomBeginOverlap, FLinearColor);
UCLASS()
class U03_CPP_API AC03_Trigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Scene;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC03_Trigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void ActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
UFUNCTION()
void ActorEndOverlap(AActor* OverlappedActor, AActor* OtherActor);
public:
FBoxLightBeginOverlap OnBoxLightBeginOverlap;
FBoxLightEndOverlap OnBoxLightEndOverlap;
};
- DECLARE_DELEGATE 활용하여 커스텀 대리자 함수 시그니처를 생성합니다.
- 커스텀 대리자 함수 시그니처를 통해 커스텀 대리자 함수를 선언합니다(eg. OnBoxLightBeginOverlap)
2. Trigger.cpp
#include "03_Collision/C03_Trigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC03_Trigger::AC03_Trigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Scene, "Scene");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Scene);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Scene);
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName());
}
void AC03_Trigger::BeginPlay()
{
Super::BeginPlay();
OnActorBeginOverlap.AddDynamic(this, &AC03_Trigger::ActorBeginOverlap);
OnActorEndOverlap.AddDynamic(this, &AC03_Trigger::ActorEndOverlap);
}
void AC03_Trigger::ActorBeginOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
// IsBound : 커스텀 대리자 함수의 바인딩이 수행되었는지 체크
if (OnBoxLightBeginOverlap.IsBound())
// Exectue : 커스텀 대리자 함수 실행
OnBoxLightBeginOverlap.Execute();
}
// FBoxLightEndOverlap 대리자 함수 시그니처와 동일한 사용자 정의 함수
void AC03_Trigger::ActorEndOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
// IsBound : 커스텀 대리자 함수의 바인딩이 수행되었는지 체크
if (OnBoxLightEndOverlap.IsBound())
// Exectue : 커스텀 대리자 함수 실행
OnBoxLightEndOverlap.Execute();
}
- IsBound() : 커스텀 대리자 함수의 "Binding"여부를 체크
- Execute() : 대리자 함수의 실행
3. Light.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Light.generated.h"
UCLASS()
class U03_CPP_API AC04_Light : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Scene;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
UPROPERTY(VisibleDefaultsOnly)
class UPointLightComponent* Light;
UPROPERTY(VisibleDefaultsOnly)
class UPointLightComponent* Light2;
public:
AC04_Light();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnLight();
UFUNCTION()
void OffLight();
};
4. Light.cpp
#include "C04_Light.h"
#include "Global.h"
#include "C03_Trigger.h"
#include "Components/TextRenderComponent.h"
#include "Components/PointLightComponent.h"
AC04_Light::AC04_Light()
{
CHelpers::CreateComponent<USceneComponent>(this, &Scene, "Scene");
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Scene);
CHelpers::CreateComponent<UPointLightComponent>(this, &Light, "Light", Scene);
CHelpers::CreateComponent<UPointLightComponent>(this, &Light2, "Light2", Scene);
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName());
//1e+4f = 10^4 = 10000;
//1e-6f = 10^-6 = 0.000001;
Light->Intensity = 1e+4f;
Light->AttenuationRadius = 200;
Light->LightColor = FColor(255, 128, 50);
Light2->SetRelativeLocation(FVector(200, 0, 0));
Light2->Intensity = 1e+4f;
Light2->AttenuationRadius = 200;
Light2->LightColor = FColor(255, 128, 50);
}
void AC04_Light::BeginPlay()
{
Super::BeginPlay();
Light->SetVisibility(false);
Light2->SetVisibility(false);
TArray<AActor*> actors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AC03_Trigger::StaticClass(), actors);
CheckFalse(actors.Num() > 0);
AC03_Trigger* trigger = Cast<AC03_Trigger>(actors[0]);
// BindUFunction: Trigger 클래스의 커스텀 대리자 함수와 "바인딩"을 수행합니다!
trigger->OnBoxLightBeginOverlap.BindUFunction(this, "OnLight");
trigger->OnBoxLightEndOverlap.BindUFunction(this, "OffLight");
}
// FBoxLightBeginOverlap 대리자 함수 시그니처와 동일한 사용자 정의 함수
void AC04_Light::OnLight()
{
Light->SetVisibility(true);
Light2->SetVisibility(true);
}
// FBoxLightEndOverlap 대리자 함수 시그니처와 동일한 사용자 정의 함수
void AC04_Light::OffLight()
{
Light->SetVisibility(false);
Light2->SetVisibility(false);
}
- BindFunction() : 대리자 함수에서 호출할 함수 포인터를 연결합니다!
Multicast
1. 기본구조
DECLARE_MULTICAST_DELEGATE_TwoParams(MULTICAST_DELEGATE_NAME, PARAM_1_TYPE, PARAM_2_TYPE);
- 기본 구조는 위와 동일합니다.
- 다만, "DECLARE_MULTICAST_DELEGATE"를 통해 반환 값이 없는 대리자 함수 시그니처를 생성합니다.
- 더불어, 대리자 함수의 실행을 "Execute"가 아니라, "Broadcast"를 통해 수행합니다.
Event
1. 기본 구조
- 위에서 살펴본 Delegate와 기본 구조는 동일합니다.
- 다만, "IsBound" + "Execute" 등의 대리자 함수의 실행은 대리자 함수가 선언된 클래스 내부에서만 가능합니다!
- 따라서, "DECLARE_DELEGATE" 대리자 함수 시그니처 선언 또한 클래스 내부에 선언합니다.
'게임개발 > Unreal C++' 카테고리의 다른 글
[Unreal]#23_FString, FText, FName 변환 (0) | 2023.02.05 |
---|---|
[Unreal]#22_TTuple (0) | 2023.02.05 |
[Unreal]#20_Log (0) | 2022.11.02 |
[Unreal]#19_Custom Behavior Tree Service (0) | 2022.10.05 |
[Unreal]#18_Custom Behavior Tree Task (0) | 2022.10.05 |