개요
이벤트 디스패처는 하나의 액터가 이벤트를 디스패치하고 해당 이벤트를 리스닝하는 다른 액터가 알림을 받는 액터 커뮤니케이션 메서드입니다.
이 메서드를 사용하면, 알림을 보내는 액터는 수신하는 액터가 구독하는 이벤트 디스패처(Event Dispatcher) 를 생성합니다. 이 커뮤니케이션 메서드는 일대다 관계를 사용하며, 작업 중인 액터가 이벤트 디스패처를 트리거하면 다수의 수신 액터가 알림을 받습니다. 이 퀵스타트 가이드에서는 이벤트 디스패처를 사용하여 레벨에서 두 개의 액터를 트리거할 OnBossDied 이벤트를 생성하는 방법을 알아봅니다.
구성
-
게임(Games) > 삼인칭(Third Person) > 블루프린트(Blueprint) 순서로 새 프로젝트를 생성하고 시작용 콘텐츠를 활성화합니다.
(w:600)
OnBossDied 이벤트 생성
-
콘텐츠 브라우저(Content Browser) 에서 우클릭한 다음 기본 에셋 생성(Create Basic Asset) 섹션에서 블루프린트 클래스(Blueprint Class) 를 클릭합니다.
-
부모 클래스로 액터(Actor) 를 선택하고 블루프린트를 BP_BossDied 로 명명합니다.
-
BP_BossDied 를 블루프린트 에디터에서 열고 뷰포트(Viewport) 에서 컴포넌트 추가(Add Component) 버튼을 클릭한 다음 Box Collision 을 검색하여 선택합니다.
-
Box 콜리전을 선택한 채 스케일을 X = 4 , Y = 4 , Z = 2 로 변경합니다.
-
Box 콜리전을 선택한 채 디테일(Details) 패널의 렌더링(Rendering) 섹션으로 이동하여 게임에서 숨김(Hidden in Game) 체크박스를 선택 해제합니다. 그러면 게임플레이 도중 콜리전 박스가 표시됩니다.
-
Box 콜리전을 우클릭하고 OnComponentBeginOverlap 추가 를 선택합니다. 이벤트 그래프(Event Graph) 에 노드가 추가됩니다.
-
왼쪽의 내 블루프린트(My Blueprint) 패널에서 이벤트 디스패처(Event Dispatchers) 섹션으로 이동하고 + 새로 추가(Add New) 를 클릭하여 새 이벤트를 추가합니다. 이 이벤트를 OnBossDied 로 명명합니다.
-
OnBossDied 를 이벤트 그래프(Event Graph) 로 드래그하고 호출(Call) 을 선택하여 노드를 추가합니다.
-
On Component Begin Overlap 노드를 Call OnBossDied 노드에 연결합니다. 블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
BP_BossDied 블루프린트를 레벨로 드래그합니다.
(w:600)
인터랙티브 문 생성
-
콘텐츠 브라우저(Content Browser) 에서 우클릭한 다음 기본 에셋 생성(Create Basic Asset) 섹션에서 블루프린트 클래스(Blueprint Class) 를 클릭합니다.
-
부모 클래스로 액터(Actor) 를 선택하고 블루프린트를 BP_BossDoor 로 명명합니다.
-
BP_BossDoor 를 열고 뷰포트(Viewport) 에서 컴포넌트 추가(Add Component) 드롭다운을 클릭한 다음 Static Mesh 를 검색하여 선택합니다. 컴포넌트를 Frame 으로 명명합니다.
-
Static Mesh 를 하나 더 추가하고 Door 로 명명합니다.
-
Frame 컴포넌트를 선택하고 디테일(Details) 패널에서 Static Mesh 드롭다운을 클릭한 뒤 SM_DoorFrame 을 검색하고 선택합니다.
-
Door 컴포넌트에도 위 단계를 반복하여 SM_Door 스태틱 메시를 추가합니다.
-
Door 컴포넌트를 선택하고 아래와 같이 Y 위치를 45 로 설정합니다. 그러면 문이 프레임에 맞춰 정렬될 것입니다.
-
이벤트 그래프 를 우클릭한 뒤 커스텀 이벤트 추가(Add Custom Event) 를 검색하고 선택합니다. 이벤트를 OpenDoor 로 명명합니다.
-
OpenDoor 이벤트에서 드래그하여 타임라인 추가(Add Timeline) 를 검색하고 선택합니다. 타임라인을 TM_Door 로 명명합니다.
-
TM_Door 를 더블클릭하여 엽니다. Float 트랙 추가(Add Float Track) 를 클릭하여 Float 트랙을 추가하고 Alpha 로 명명합니다. 길이를 1.0 으로 설정합니다.
-
그래프에서 우클릭한 뒤 CurveFloat_1에 키 추가(Add key to CurveFloat_1) 를 선택하여 새 포인트를 추가합니다. 시간(Time) 및 값(Value) 을 0.0 으로 설정합니다.
-
위 단계를 반복하여 포인트를 하나 더 추가하고 시간(Time) 과 값(Value) 을 1.0 으로 설정합니다.
-
이벤트 그래프(Event Graph) 로 돌아가서 Door 스태틱 메시 컴포넌트를 이벤트 그래프 로 드래그하여 노드를 생성합니다. Door 노드에서 드래그하여 SetRelativeRotation 을 검색하고 선택합니다.
-
TM_Door 의 Update 핀을 SetRelativeRotation 노드에 연결합니다. New Rotation 핀을 우클릭하고 구조체 핀 분할(Split Struct Pin) 을 선택합니다.
-
이벤트 그래프(Event Graph) 를 우클릭한 뒤 Lerp Float 를 검색하고 선택합니다. Return Value 를 SetRelativeRotation 노드의 Yaw 핀에 연결합니다. TM_Door 의 Alpha 핀을 Lerp 노드의 Alpha 핀에 연결합니다. 마지막으로 B 값을 아래와 같이 90.0 으로 설정합니다.
-
변수(Variable) 섹션 옆의 + 버튼 을 클릭하여 새 변수를 추가합니다. 변수를 BossDiedReference 로 명명합니다.
-
디테일(Details) 패널에서 변수 타입(Variable Type) 드롭다운을 클릭한 다음 BP_BossDied의 오브젝트 레퍼런스(Object Reference) 를 검색하여 선택합니다. 인스턴스 편집가능(Instance Editable) 체크박스를 체크합니다.
-
BossDiedReference 를 이벤트 그래프(Event Graph) 로 드래그하여 GetBossDiedReference 를 선택합니다. 노드에서 드래그하여 Bind Event to On Boss Died 를 검색하고 선택합니다.
-
Bind Event to On Boss Died 의 빨간색 이벤트(Event) 핀에서 드래그하여 커스텀 이벤트 추가(Add Custom Event) 를 검색하고 선택합니다. 이벤트를 BossDied 로 명명합니다.
-
BossDied 이벤트 노드에서 드래그하여 Open Door 를 검색하고 선택합니다. Event Begin Play 를 아래와 같이 Bind Event to On Boss Died 노드에 연결합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
이벤트 디스패처 테스트하기
-
BP_BossDoor 액터를 레벨로 드래그합니다. 디테일(Details) 패널에서 Boss Reference Died 드롭다운을 클릭한 다음 BP_BossDied 를 검색하고 선택합니다.
(w:600)
-
플레이 를 누르고 BP_BossDied 트리거로 걸어가서 게임 내 보스의 사망을 시뮬레이션합니다.
(convert:false)
다음 단계
이제 이벤트 디스패처의 사용법을 배웠으니 액터 커뮤니케이션 문서 페이지에 있는 다른 커뮤니케이션 타입에 대해서도 알아보세요.
개요
델리게이트(Delegates)는 액터 클래스 블루프린트에서 타입 안전(type-safe) 방식으로 메서드를 호출할 수 있습니다. 델리게이트는 하나의 액터가 리슨하는 다른 액터에서 이벤트를 트리거하여 해당 이벤트에 대한 알림을 받는 커뮤니케이션을 형성하도록 동적으로 바인딩할 수 있습니다.
더 자세히 알아보려면 델리게이트 문서를 참고하세요.
목표
이 퀵스타트 가이드에서는 델리게이트를 사용하여 레벨에서 두 개의 액터 클래스 블루프린트를 트리거할 OnBossDied 이벤트를 생성하는 방법을 알아봅니다.
세부 목표
-
OnBossDied 델리게이트를 포함할 Boss 액터를 생성합니다.
-
OnBossDied 이벤트에 바인딩될 타임라인 컴포넌트가 있는 인터랙티브 문 액터를 생성합니다.
1 - 필수 구성
-
메뉴의 새 프로젝트 카테고리(New Project Categories) 섹션에서 게임(Games) 을 선택하고 다음(Next) 을 클릭합니다.
-
삼인칭(Third Person) 템플릿을 선택하고 다음(Next) 을 클릭합니다.
-
C++ 및 시작용 콘텐츠 포함(With Starter Content) 옵션을 선택하고 프로젝트 생성(Create Project) 을 클릭합니다.
섹션 결과
이제 새로운 C++ 삼인칭 프로젝트가 생성되었으며, 델리게이트를 알아볼 준비가 되었습니다.
2 - Boss 액터 및 OnBossDied 델리게이트 생성
-
C++ 클래스 마법사(C++ Class Wizard)에서 BossActor 라는 이름의 새 액터 클래스를 생성합니다.
-
BossActor.h 로 이동합니다. 라이브러리 include 아래에 다음 델리게이트를 선언합니다.
DECLARE_DELEGATE(FOnBossDiedDelegate);
-
클래스 디폴트에 다음을 선언합니다.
protected: UFUNCTION() void HandleBossDiedEvent(); UPROPERTY(EditInstanceOnly, BlueprintReadWrite) class UBoxComponent* BoxComp; virtual void NotifyActorBeginOverlap(AActor* OtherActor); public: FOnBossDiedDelegate OnBossDied;
-
BossActor.cpp로 이동하여 다음 클래스 라이브러리를 추가합니다.
#include "Components/BoxComponent.h"
-
다음 클래스 정의를 구현합니다.
ABossActor::ABossActor() { BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp")); BoxComp->SetBoxExtent(FVector(128, 128, 64)); BoxComp->SetVisibility(true); } void ABossActor::HandleBossDiedEvent() { OnBossDied.ExecuteIfBound(); } void ABossActor::NotifyActorBeginOverlap(AActor* OtherActor) { HandleBossDiedEvent(); }
-
코드를 컴파일(Compile) 합니다.
-
C++ 클래스 폴더(C++ Classes folder) 에서 BossActor 를 우클릭한 다음 C++ 클래스 액션(C++ Class Actions) 드롭다운 메뉴에서 BossActor 기반 블루프린트 클래스 생성(Create Blueprint class based on BossActor) 을 선택합니다. 블루프린트 클래스의 이름을 BP_BossActor 로 지정합니다.
-
BossActor 의 인스턴스를 레벨로 드래그합니다.
완성된 코드
BossActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BossActor.generated.h"
DECLARE_DELEGATE(FOnBossDiedDelegate);
UCLASS()
class BPCOMMUNICATION_API ABossActor : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 디폴트값 설정
ABossActor();
protected:
// 게임 시작 또는 스폰 시 호출
virtual void BeginPlay() override;
UFUNCTION()
void HandleBossDiedEvent();
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
class UBoxComponent* BoxComp;
virtual void NotifyActorBeginOverlap(AActor* OtherActor);
public:
// 프레임마다 호출
virtual void Tick(float DeltaTime) override;
FOnBossDiedDelegate OnBossDied;
};
BossActor.cpp
#include "BossActor.h"
#include "Components/BoxComponent.h"
#include "BPCommunicationGameMode.h"
// 디폴트값 설정
ABossActor::ABossActor()
{
// 이 액터가 프레임마다 Tick()을 호출하도록 설정합니다. 이 설정이 필요 없는 경우 비활성화하면 퍼포먼스가 향상됩니다.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
BoxComp->SetBoxExtent(FVector(128, 128, 64));
BoxComp->SetVisibility(true);
}
// 게임 시작 또는 스폰 시 호출
void ABossActor::BeginPlay()
{
Super::BeginPlay();
}
void ABossActor::HandleBossDiedEvent()
{
OnBossDied.ExecuteIfBound();
}
void ABossActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
HandleBossDiedEvent();
}
// 프레임마다 호출
void ABossActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
섹션 결과
이 섹션에서는 박스 컴포넌트를 포함하는 BossActor 클래스와 OnBossDied 이벤트에 대한 델리게이트를 생성했습니다. 이 델리게이트는 해당 이벤트가 실행될 때 다른 액터 클래스에 신호를 보내는 용도로 사용됩니다.
3 - 인터랙티브 문 생성
-
C++ 클래스 마법사(Class Wizard) 에서 DoorActor 라는 이름의 신규 액터(Actor) 클래스를 만듭니다.
-
DoorActor.h 파일로 이동한 뒤 다음을 선언합니다.
#include "Components/TimelineComponent.h"
-
다음 클래스 정의를 선언합니다.
// 커브 에셋을 보관하는 변수 UPROPERTY(EditInstanceOnly) UCurveFloat* DoorTimelineFloatCurve; protected: void BossDiedEventFunction(); UPROPERTY(EditInstanceOnly,BlueprintReadWrite) class ABossActor* BossActorReference; //문 에셋을 나타내는 MeshComponents UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* DoorFrame; UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UStaticMeshComponent* Door; //문 메시를 애니메이팅하는 TimelineComponent UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UTimelineComponent* DoorTimelineComp; //업데이트 트랙 이벤트를 처리할 float 트랙 시그니처 FOnTimelineFloat UpdateFunctionFloat; //타임라인 그래프에 따라 문의 상대적 위치를 업데이트하는 함수 UFUNCTION() void UpdateTimelineComp(float Output);
-
DoorActor.cpp 에서 다음 클래스 라이브러리를 선언합니다.
#include "BossActor.h"
-
다음 클래스 정의를 구현합니다.
ADoorActor::ADoorActor() { //디폴트 컴포넌트 생성 DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh")); Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh")); DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp")); //어태치먼트 구성 DoorFrame->SetupAttachment(RootComponent); Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform); Door->SetRelativeLocation(FVector(0, 35, 0)); } // 게임 시작 또는 스폰 시 호출 void ADoorActor::BeginPlay() { Super::BeginPlay(); //Float 트랙을 UpdateTimelineComp 함수의 출력에 바인딩 UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp); //Float 커브가 있는 경우 그래프를 업데이트 함수에 바인딩 if (DoorTimelineFloatCurve) { DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat); } if (BossActorReference) { BossActorReference->OnBossDied.BindUObject(this, &ADoorActor::BossDiedEventFunction); } } void ADoorActor::BossDiedEventFunction() { DoorTimelineComp->Play(); } void ADoorActor::UpdateTimelineComp(float Output) { // 타임라인 커브(Timeline Curve)의 출력을 바탕으로 문의 새 상대적 위치 설정 및 구성 FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f); Door->SetRelativeRotation(DoorNewRotation); }
-
코드를 컴파일합니다.
-
콘텐츠 브라우저(Content Browser) 에서 추가/임포트(Add/Import) > 기타(Miscellaneous) > 커브(Curve) 를 선택합니다.
-
CurveFloat 를 선택하고 CurveFloat 에셋을 DoorCurveFloat 로 명명한 다음 DoorCurveFloat 에셋을 더블클릭합니다. float 커브에 두 개의 키를 추가하고 시간 값을 각각 (0, 0)과 (4, 90)으로 설정합니다.
-
Shift+클릭하여 두 키를 함께 선택한 다음 자동 큐빅 보간(Auto Cubic interpolation) 으로 설정하고 커브를 저장합니다.
-
DoorCurveFloat를 저장합니다.
-
콘텐츠 브라우저에서 C++ 클래스(C++ Classes) 폴더로 이동하여 DoorActor 클래스를 우클릭한 다음 DoorActor 기반 블루프린트 클래스 생성(Create Blueprint class based on DoorActor) 을 선택합니다. 블루프린트 액터를 BP_DoorActor 로 명명합니다.
-
BP_DoorActor 의 클래스 디폴트(class defaults) 에서 컴포넌트(Components) 탭을 찾고 DoorFrame 스태틱 메시 컴포넌트(Static Mesh component) 를 선택한 다음, 디테일(Details) 패널로 이동하여 스태틱 메시를 SM_DoorFrame 으로 변경합니다.
-
컴포넌트 탭에서 DoorMesh 컴포넌트를 선택합니다. 디테일 패널로 이동한 뒤 스태틱 메시를 SM_Door 로 변경합니다.
-
디테일 패널의 Door Timeline Float Curve 드롭다운 메뉴에서 DoorCurveFloat를 선택합니다.
-
블루프린트를 컴파일하고 저장합니다.
완성된 코드
DoorActor.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "DoorActor.generated.h"
UCLASS()
class BPCOMMUNICATION_API ADoorActor : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 디폴트값 설정
ADoorActor();
// 커브 에셋을 보관하는 변수
UPROPERTY(EditInstanceOnly)
UCurveFloat* DoorTimelineFloatCurve;
protected:
// 게임 시작 또는 스폰 시 호출
virtual void BeginPlay() override;
void BossDiedEventFunction();
UPROPERTY(EditInstanceOnly,BlueprintReadWrite)
class ABossActor* BossActorReference;
//문 에셋을 나타내는 MeshComponents
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* DoorFrame;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UStaticMeshComponent* Door;
//문 메시를 애니메이팅하는 TimelineComponent
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* DoorTimelineComp;
//업데이트 트랙 이벤트를 처리할 float 트랙 시그니처
FOnTimelineFloat UpdateFunctionFloat;
//타임라인 그래프에 따라 문의 상대적 위치를 업데이트하는 함수
UFUNCTION()
void UpdateTimelineComp(float Output);
public:
// 프레임마다 호출
virtual void Tick(float DeltaTime) override;
};
DoorActor.cpp
#include "DoorActor.h"
#include "BossActor.h"
// 디폴트값 설정
ADoorActor::ADoorActor()
{
// 이 액터가 프레임마다 Tick()을 호출하도록 설정합니다. 이 설정이 필요 없는 경우 비활성화하면 퍼포먼스가 향상됩니다.
PrimaryActorTick.bCanEverTick = true;
//디폴트 컴포넌트 생성
DoorFrame = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrameMesh"));
Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh"));
DoorTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("DoorTimelineComp"));
//어태치먼트 구성
DoorFrame->SetupAttachment(RootComponent);
Door->AttachToComponent(DoorFrame, FAttachmentTransformRules::KeepRelativeTransform);
Door->SetRelativeLocation(FVector(0, 35, 0));
}
// 게임 시작 또는 스폰 시 호출
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
//Float 트랙을 UpdateTimelineComp 함수의 출력에 바인딩
UpdateFunctionFloat.BindDynamic(this, &ADoorActor::UpdateTimelineComp);
//Float 커브가 있는 경우 그래프를 업데이트 함수에 바인딩
if (DoorTimelineFloatCurve)
{
DoorTimelineComp->AddInterpFloat(DoorTimelineFloatCurve, UpdateFunctionFloat);
}
if (DoorTimelineFloatCurve)
{
BossActorReference->OnBossDied.BindUObject(this, &ADoorActor::BossDiedEventFunction);
}
}
void ADoorActor::BossDiedEventFunction()
{
DoorTimelineComp->Play();
}
void ADoorActor::UpdateTimelineComp(float Output)
{
// 타임라인 커브(Timeline Curve)의 출력을 바탕으로 문의 새 상대적 위치 설정 및 구성
FRotator DoorNewRotation = FRotator(0.0f, Output, 0.f);
Door->SetRelativeRotation(DoorNewRotation);
}
// 프레임마다 호출
void ADoorActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
섹션 결과
이 섹션에서는 BossActor 클래스에 있는 OnBossDied 이벤트 디스패처에 바인딩되는 인터랙티브 DoorActor 를 생성했습니다. 이 바인딩은 Begin Play에서 발생하지만 BossActor의 박스 컴포넌트(Box Component) 오버랩이 이벤트를 트리거할 때마다 런타임에서 실행됩니다.
5 - 이벤트 디스패처 테스트
-
BP_Door 블루프린트를 레벨로 드래그합니다. 디테일(Details) 패널로 이동하여 보스 레퍼런스 사망(Boss Reference Died) 드롭다운을 클릭하고 BP_BossDied 를 검색하여 선택합니다.
-
Bp_DoorActor가 선택된 상태로 디테일 패널에서 보스 액터 레퍼런스(Boss Actor Reference) 드롭다운 화살표를 클릭한 다음 BP_BossActpr 를 검색하여 선택합니다.
-
플레이를 누르고 BP_BossActor 트리거로 걸어가서 게임 내 보스의 사망을 시뮬레이션합니다.
섹션 결과
이 섹션에서는 레벨에서 BP_DoorActor 를 테스트했습니다. BP_BossActor의 박스 컴포넌트 가 다른 액터와 오버랩되어 델리게이트를 트리거하면 액터가 OnBossDied 에 반응한다는 것을 확인했습니다.
이 가이드에서는 델리게이트를 사용하여 다수의 액터 클래스 블루프린트 간에 커뮤니케이션하는 방법을 배웠습니다.
다음 단계
지금까지 델리게이트 사용법을 알아보았습니다. 액터 커뮤니케이션 문서 페이지에 나와 있는 다른 커뮤니케이션 타입도 확인해 보세요.