Unreal

20. Observer Pattern & Delegate

Kelvin의 게임개발 2024. 2. 7. 00:13
728x90
반응형

1. Observer Pattern & Delegate

 

우선 Observer Pattern에 대해서 알아보자

 

Subject가 있고 이 Subject는 Observer List를 가지고 있다 이 Observer List의 Observer들은 프로그램에 존재하는 다른 Observer를 의미한다 (여기서 Observer는 Object로 생각해도 됨)

 

프로젝트에 존재하는 Observer들은 CallBack()함수를 가지고 있고 Observer는 특정한 상황에서 이 CallBack()함수가 호출되길 원한다 이를 Event라고 부른다

 

Observer Pattern의 목표는 Subject의 Observer들의 CallBack()함수를 특정 Event때 호출하는 것이다

 

결국에 Subject는 Event가 언제 발생하는지 알고 해당 Event때 Subject가 갖고 있는 특정 Observer의 CallBack()함수를 호출한다

 

이러한 Observer Pattern을 UE에서 Delegate로 구현할 수 있다

 

Delegate는 Subject의 Observer List를 저장할 수 있는 특별한 타입의 클래스이다

 

게임에서 Event가 발생하면 Subject는 해당 Observer에게 알려주고 Observer List들의 CallBack()함수를 호출한다

 

 

Delegate를 사용할 때는 Observer들의 CallBack()함수를 Bind 시킨 후 호출해야 한다, 호출 시 CallBack()함수의 매개변수를 인자로 넘겨야 한다 (Delegate와 CallBack()함수의 매개변수는 일치해야 한다)

 

 

USphereComponent에서 OnComponentBeginOverlap Event를 사용할 수 있는 이유는 부모클래스인 UPrimitiveComponent에 OnComponentBeginOverlap Delegate가 있기 때문이다

 

 

그렇다면 Delegate를 C++에서 어떻게 Bind()하고 Call()하는지 알아보자

 

UE에는 총 4가지 종류의 Delegate가 있다

Single Cast : 가장 기본적인 Delegate로 함수 1개를 Bind 하여 사용

Multi Cast : Single Cast와 동일하지만 여러 함수를 Bind 할 수 있다
Event : Multi Cast와 동일하지만 전역으로 설정할 수 없어 외부 클래스에서 추가 Delegate 선언이 불가능하다

Dynamic Cast : Single과, Multi 두 개 다 존재하며 Dynamic Cast는 직렬화(Serialize)되어 BP에서 사용 가능하다

 

 

<Delegate 선언>

DECLARE_DELEGATE(FDele_Single); //Delegate 이름 앞에는 항상 F접두사를 붙혀야 한다
DECLARE_DELEGATE_OneParam(FDele_Single_OneParam, int32); //One, Two, Three로 매개변수 개수 변경이 가능하며 타입만 작성한다

DECLARE_MULTICAST_DELEGATE(FDele_Multi); //Delegate 이름 앞에는 항상 F접두사를 붙혀야 한다
DECLARE_MULTICAST_OneParam(FDele_Multi_OneParam, int32); //One, Two, Three로 매개변수 개수 변경이 가능하며 타입만 작성한다

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDele_DynamicMulti); //Delegate 이름 앞에는 항상 F접두사를 붙혀야 한다
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDele_DynamicMulti_OneParam, int32, InValue); //One, Two, Three로 매개변수 개수 변경이 가능하며 타입과 Input변수 둘 다 작성한다

UCLASS()
class DELEGATETEST_API AItem : public AActor
{
	GENERATED_BODY()
public:
	//Event는 매개변수로 자기자신 Class명을 앞에 넣어야 한다
	//Event는 전역으로 선언이 불가능
	DECLARE_EVENT(AItem, FDele_Event);
	DECLARE_EVENT_OneParam(AItem, FDele_Event_OneParam, int32);
	
	//Delegate를 가져올 때 값전달보다 참조 전달로 가져오는것이 좋다 (중요)
	&FDele_Single GetFuc_DeleSingle() { return Fuc_DeleSingle; }
    
public:
	 //Delegate변수
	FDele_Single Fuc_DeleSingle;
	FDele_Single_OneParam Fuc_DeleSingle_OneParam;
    
	FDele_Multi Fuc_DeleMulti;
	FDele_Multi_OneParam Fuc_DeleMulti_OneParam;
    
	FDele_Event Fuc_DeleEvent;
	FDele_Event_OneParam Fuc_DeleEvent_OneParam;
    
	//Dynamic은 BP에서 사용하기 위해서는 UPROPERYT()지정자들이 필요하다
	UPROPERTY(BlueprintAssignable, VisibleAnywhere, BlueprintCallable, Category = "Event")
	FDele_DynamicMulti Fuc_Dynamic;

	UPROPERTY(BlueprintAssignable, VisibleAnywhere, BlueprintCallable, Category = "Event")
	FDele_DynamicMulti_OneParam Fuc_Dynamic_OneParam;
};

 

 

<Delegate Bind해제, Bind확인, 호출>

void AItem::DestoryItem()
{
	//SingleCast
	Fuc_DeleSingle.Unbind(); //Unbind()로 Bind해제
	Fuc_DeleSingle_OneParam.Unbind(); //Unbind()로 Bind해제
    
	//MultiCast & Dynamic(동일)
	Fuc_DeleMulti.Clear(); //Claer()로 Bind해제
 	Fuc_DeleMulti_OneParam.Clear(); //Claer()로 Bind해제
}

void AItem::ActiveItem()
{
	//SingleCast
	//IsBound()로 Bind되었는지 확인이 가능하다 (T/F)
	if(Fuc_DeleSingle.IsBound()==true)	
    	Fuc_DeleSingle.Execute(); //Execute()로 Delegate호출한다
        
	if(Fuc_DeleSingle_OneParam.IsBound() == true) 
    	Fuc_DeleSingle_OneParam.Execute(10); //Execute()로 Delegate호출한다
        
	
	//MultiCast & Dynamic(동일)
	//IsBound()로 Bind되었는지 확인이 가능하다 (T/F)
	if(Fuc_DeleMulti.IsBound() == true) 
    	Fuc_DeleMulti.Broadcast(); //Broadcast()로 Delegate호출한다
        
	if(Fuc_DeleMulti_OneParam.IsBound() == true) 
    	Fuc_DeleMulti_OneParam.Broadcast(10); //Broadcast()로 Delegate호출한다
}

 

 

<Delegate용 함수>

UCLASS()
class DELEGATETEST_API APlayer : public AActor
{
	GENERATED_BODY()
public:	

	//Delegate에 Bind될 함수들이다, Deleagte의 인자와 함수의 매개변수는 일치해야 한다
	//UFUNCTION()을 무조건 붙혀야 함
	UFUNCTION()
	void DelegateTestFunction();
	UFUNCTION()
	void DelegateTestFunctionOneParam(int32 InValue);

 

 

<Delegate에 함수 Bind>

void APlayer::BeginPlay()
{
	//SingleCast
	ItemA->Fuc_DeleSingle.BindUFunction(this, FName("DelegateTestFunction"));
	ItemA->Fuc_DeleSingle_OneParam.BindUFunction(this, FName("DelegateTestFunctionOneParam"));
    
	//MultiCast
	ItemA->Fuc_DeleMulti.AddUFunction(this, FName("DelegateTestFunction"));
	ItemA->Fuc_DeleMulti_OneParam.AddUFunction(this, FName("DelegateTestFunctionOneParam"));
    
	//Dynamic
	ItemA->Fuc_Dynamic.AddDynamic(this, &APlayer::DelegateTestFunction);
	ItemA->Fuc_Dynamic_OneParam.AddDynamic(this, &APlayer::DelegateTestFunctionOneParam);
    
	//BindUFunction, AddUFunction보다는 AddUObject를 사용하는걸 권장한다 (AddDynamic제외)
	ItemA->Fuc_DeleSingle.AddUObject(this, &APlayer::DelegateTestFunction);
	ItemA->Fuc_DeleSingle_OneParam.AddUObject(this, &APlayer::DelegateTestFunctionOneParam);
	
	ItemA->Fuc_DeleMulti.AddUObject(this, &APlayer::DelegateTestFunction);
	ItemA->Fuc_DeleMulti_OneParam.AddUObject(this, &APlayer::DelegateTestFunctionOneParam);
}

 

 

728x90
반응형

'Unreal' 카테고리의 다른 글

22. IK Rig And Retarget & Socket & fbx Import  (70) 2024.02.15
21. Collision & Overlap (2)  (79) 2024.02.08
19. Collision & Overlap (1)  (117) 2024.01.31
18. IK (Inverse Kinematics)  (109) 2024.01.27
17. Jump Animation  (125) 2024.01.24