언리얼 C++ 프로그래밍

[언리얼 C++] 이벤트

언린이 2021. 7. 2. 17:39

언리얼 엔진에서 이벤트는 여러 함수를 바인딩하여 모두 동시에 실행시킬 수 있는 델리게이트입니다.

 

이벤트는 멀티캐스트 델리게이트와 매우 유사합니다. (멀티캐스트 델리게이트에 대한 설명은 [언리얼 C++] 멀티캐스트 델리게이트 (tistory.com) 글을 참고하시기 바랍니다.)

이벤트도 멀티캐스트 델리게이트와 마찬가지로 아무 클래스에서나 함수 바인딩이 가능합니다.

하지만 이벤트는 멀티캐스트 델리게이트와 다른 점이 있습니다. 바로 멀티캐스트 델리게이트는 아무 클래스에서나 해당 델리게이트의 함수를 호출할 수 있는데, 이벤트는 해당 이벤트를 선언한 클래스만이 이벤트의 Broadcast(), IsBound(), Clear() 함수를 호출할 수 있습니다.

즉, 이벤트 오브젝트는 퍼블릭 인터페이스에 노출시켜도 Broadcast(), IsBound(), Clear() 함수에 대한 접근권을 외부 클래스에게 제공하지 않을 수 있습니다. 이러한 특징때문에 이벤트가 사용되는때는 순수 추상 클래스의 콜백을 포함시킬때나, 외부 클래스에게 Broadcast(), IsBound(), Clear() 함수 호출을 제한시킬때 입니다.

 

 

1. 이벤트 선언하기

언리얼 엔진에서는 이벤트 선언을 위해서 여러가지 매크로를 제공하고 있습니다.

사용되는 매크로는 이벤트에 바인딩되는 함수의 시그너처에 따라 결정됩니다.

 

DECLARE_EVENT(OwningType, EventName) // 이벤트를 생성합니다.

DECLARE_EVENT_OneParam(OwningType, EventName, Param1Type) // 파라미터가 하나인 이벤트를 생성합니다.

DECLARE_EVENT_<Num>Params(OwningType, EventName, Param1Type, Param2Type, ...) // 파라미터가 Num개인 이벤트를 생성합니다.

위의 코드처럼 바인딩되는 함수의 파라미터 개수에 따라 다양한 이벤트를 선언할 수 있습니다.

 

 

2. 이벤트 바인딩하기

이벤트에 함수를 바인딩하는 방법은 멀티캐스트 델리게이트에서의 방법과 완전히 동일합니다.

 

함수 설명
Add() 멀티캐스트 델리게이트의 실행 목록에 함수 델리게이트를 추가합니다.
AddStatic() raw C++ 포인터 글로벌 함수 델리게이트를 추가합니다.
AddRaw() raw C++ 포인터 델리게이트를 추가합니다.
raw 포인터는 어떠한 레퍼런스도 사용하지 않기에, 오브젝트가 자신의 델리게이트 하에서 삭제된 경우 호출시 안전하지 않을 수 있습니다.
AddSP() 공유 포인터 기반 (빠르지만 스레드 안전성은 떨어지는) 멤버 함수 델리게이트를 추가합니다. 공유 포인터 델리게이트는 자신의 오브젝트에 대한 약 레퍼런스를 유지합니다.
AddUObject() UObject 기반 멤버 함수 델리게이트를 추가합니다. UObject 델리게이트는 자신의 오브젝트에 대한 약 레퍼런스를 유지합니다.
Remove() 멀티캐스트 델리게이트의 실행 목록에서 함수를 제거합니다. 참고로 델리게이트 순서는 유지되지 않을 수 있습니다!
RemoveAll() 지정된 UserObject에 바인딩된 멀티캐스트 델리게이트의 실행 목록의 모든 함수를 제거합니다.

위의 함수들을 사용하여 바인딩해주면 됩니다. (자세한 내용은 [언리얼 C++] 멀티캐스트 델리게이트 (tistory.com) 글을 참고하시기 바랍니다.)

 

DECLARE_EVENT(ASampleActor, FChangedAttackMotion)

UCLASS()
class TestProject_API ASampleActor : public AActor
{
	GENERATED_BODY()
    
public :
	FChangedAttackMotion& OnChangedAttackMotion() { return ChangedAttackMotion; }
    
private :
	FChangedAttackMotion ChangedAttackMotion;
};

액터 클래스를 상속받은 클래스에서 공격 모션이 변경될때 호출될 이벤트를 선언해주었습니다.

 

USampleAnim::NativeInitializeAnimation()
{
	Super::NativeInitializeAnimation();
    
    ASampleActor* pActor = Cast<ASampleActor>(TryGetPawnOwner());
    
    pActor->OnChangedAttackMotion().AddUObject(this, &USampleAnim::AttackEnd);
    pActor->OnChangedAttackMotion().AddUObject(this, &USampleAnim::PlayerUpdateStat);
    pActor->OnChangedAttackMotion().AddUObject(this, &USampleAnim::NextAttackMotion);
}

그리고 AddUObject() 함수를 사용하여 선언해준 이벤트에 여러 함수들을 바인딩해주었습니다.

이제 해당 이벤트의 실행 함수를 호출하면 바인딩된 모든 함수들이 실행될 것입니다.

하지만 글 처음 이벤트와 멀티캐스트 델리게이트의 차이점에서 설명드렸듯이, 이벤트의 Broadcast() 함수는 해당 이벤트를 선언한 클래스에서만 호출할 수 있습니다.

 

 

3. 이벤트 실행하기

함수 설명
Broadcast() 이벤트를 만료되었을 수 있는 모든 바인딩 오브젝트에 브로드캐스트(전파)합니다.

이벤트는 멀티캐스트 델리게이트와 마찬가지로 Broadcast() 함수를 호출하여 바인딩된 모든 함수들을 동시에 실행시킵니다. 또한, Broadcast() 함수를 사용한 호출은 이벤트에 바인딩된 함수가 존재하지 않더라도 항상 안전합니다.

 

ChangedAttackMotion.Broadcast();

위 예제 코드처럼 해당 이벤트가 선언된 ASampleActor 클래스 내부에서 이벤트의 Broadcast() 함수를 호출만 해주면 바인딩된 모든 함수들이 실행될 것입니다.

 

 

이렇게 이벤트를 사용하는 방법에 대해 알아보았습니다.

이벤트는 멀티캐스트 델리게이트와 비슷한 점이 많지만 실행 함수를 외부 클래스에서 사용할 수 없다는 차이점을 가지고 있습니다. 그러므로 선언한 델리게이트의 실행에 대한 접근을 외부로부터 완전히 차단하고 싶을때 이벤트를 사용하시면 쉽게 구현하실 수 있을 것입니다.