이벤트 디스패처의 기본 사용법
지난 절에서 다룬 직접 참조 통신은 간단하고 명확하지만, 호출 측이 대상 블루프린트의 구체 타입을 알아야 하는 강한 결합(Tight Coupling) 문제가 있습니다. 이 구조는 확장성과 유지보수성에 부담을 줄 수 있습니다.
이번 절에서는 이 문제를 줄이고 느슨한 결합(Loose Coupling)을 가능하게 하는 통신 기법, 이벤트 디스패처(Event Dispatcher)를 다룹니다.
이벤트 디스패처란 무엇인가?
이벤트 디스패처는 특정 이벤트가 발생했음을 알리는 신호기와 같습니다. 그리고 이 신호를 듣고 싶은 블루프린트들은 이 신호기에 자신을 등록(Bind) 해두고, 신호가 발생했을 때 자신이 할 일을 지정(Assign) 해둡니다.
즉, 이벤트 디스패처는 내가 어떤 일이 일어났을 때 알려줄게. 듣고 싶은 사람은 등록해 줘.라고 말하는 것과 같습니다. 이 방식은 직접 참조와 달리, 신호를 보내는 쪽(디스패처를 호출하는 쪽)이 신호를 받는 쪽(디스패처에 등록한 쪽)이 누구인지, 어떤 타입인지 전혀 알 필요가 없게 만듭니다. 그저 특정 신호를 발생시킨다는 사실만 알면 됩니다.
이벤트 디스패처의 핵심 개념- 생성 (Create): 이벤트를 알릴 디스패처를 정의합니다.
- 바인드 (Bind): 특정 블루프린트가 디스패처에 나는 이 신호를 들을 준비가 되었어라고 등록합니다.
- 호출 (Call / Dispatch): 디스패처를 소유한 블루프린트가 신호를 발생시킨다는 의미로 디스패처를 호출합니다.
- 언바인드 (Unbind): 더 이상 신호를 듣고 싶지 않을 때 등록을 해제합니다.
이벤트 디스패처 생성 및 정의
이벤트 디스패처는 특정 액터 블루프린트 내부에 정의됩니다. 예를 들어, BP_Door가 열릴 때 다른 액터들에게 알리고 싶다면, BP_Door 내부에 디스패처를 만듭니다.
액터 블루프린트 열기: BP_Door 블루프린트 에디터를 엽니다. (예시를 위해 새롭게 BP_Door 액터 블루프린트를 만들어봅시다.)
- 좌측 변수(Variables) 패널 아래의 이벤트 디스패처(Event Dispatchers) 패널로 이동합니다.
- 패널 상단의
+ 이벤트 디스패처(+ Event Dispatcher)버튼을 클릭합니다. - 이름을 지정합니다. (예:
OnDoorOpened)
- 생성된
OnDoorOpened디스패처를 선택합니다. - 디테일 패널에서
입력(Inputs)섹션을 찾아+버튼을 클릭합니다. - 예를 들어, 문을 연 액터가 누구인지 함께 알리고 싶다면
OpeningActor(Actor Reference 타입)라는 입력 매개변수를 추가할 수 있습니다. - 이렇게 정의된 매개변수는 디스패처가 호출될 때 함께 전달됩니다.
컴파일 및 저장: 디스패처를 정의한 후에는 블루프린트를 컴파일하고 저장합니다.
이벤트 디스패처 호출(Call)하기
디스패처를 호출하는 것은 신호를 발생시킨다는 의미입니다. 디스패처를 호출하면 해당 디스패처에 바인드된 모든 함수나 이벤트가 동시에 실행됩니다.
호출 노드 배치BP_Door블루프린트의 이벤트 그래프로 이동합니다.- 만약 문을 여는
OpenDoor함수(Function)가 있다면 그 함수 로직의 끝에, 또는Event Interact로직의 특정 시점에 디스패처를 호출하도록 연결합니다. - 좌측 이벤트 디스패처 패널에서
OnDoorOpened디스패처를 드래그하여 그래프에 놓으면,Call OnDoorOpened(또는Dispatch OnDoorOpened) 노드가 생성됩니다. - 이 노드를 문이 열리는 로직의 적절한 위치에 실행 핀으로 연결합니다.
- 만약
OpeningActor입력 매개변수가 있다면, 이 노드의 해당 핀에 문을 연 액터의 레퍼런스를 연결해줍니다.
이벤트 디스패처에 바인드(Bind)하기
이제 다른 블루프린트(예: BP_PlayerCharacter 또는 BP_GameManager)가 BP_Door의 OnDoorOpened 이벤트를 듣고 반응하도록 바인드해봅시다.
듣고 싶은 블루프린트 열기: BP_GameManager 또는 BP_PlayerCharacter 블루프린트를 엽니다. (편의상 BP_GameManager를 새로 만들어 사용해봅시다. 부모 클래스는 Actor로 생성합니다.)
- 이 블루프린트가
BP_Door액터 인스턴스를 알아야 바인드할 수 있습니다. 가장 간단한 방법은Event BeginPlay에서Get All Actors Of Class노드를 사용하여 월드의BP_Door액터를 가져오는 것입니다. - 주의:
Get All Actors Of Class는 배열을 반환하므로, 첫 번째 요소(Get (a copy))를 가져오거나For Each Loop를 사용하여 모든 문에 바인드할 수 있습니다. - 가져온
BP_Door액터 레퍼런스를 변수(예:MyDoorRef, BP_Door Object Reference 타입)로 승격시켜 저장해두면 편리합니다.
BP_GameManager블루프린트의Event BeginPlay뒤에, 또는 적절한 초기화 로직 뒤에, 앞서 가져온MyDoorRef변수(Get 노드)의 출력 핀에서 드래그하여Bind Event to OnDoorOpened노드를 검색하고 선택합니다.Target핀에는MyDoorRef를 연결합니다.Event핀에는 디스패처가 호출될 때 실행될커스텀 이벤트(Custom Event)를 연결해야 합니다.
Bind Event to OnDoorOpened노드의Event핀에서 드래그하여Custom Event를 검색하고Add Custom Event를 선택합니다.- 새로운 커스텀 이벤트 노드가 생성됩니다. 이름을
HandleDoorOpenEvent와 같이 지정합니다. - 만약
OnDoorOpened디스패처에OpeningActor와 같은 입력 매개변수가 있었다면, 이 커스텀 이벤트 노드에도 자동으로 해당 매개변수 핀이 생성됩니다. - 이제
HandleDoorOpenEvent노드의 실행 핀 뒤에 디스패처 신호를 받았을 때 수행할 로직을 구현합니다. - 예시:
Print String노드를 연결하여 게임 매니저: 문이 열렸습니다! 연 사람: 을 출력하고,OpeningActor핀을Append노드와 연결하여 메시지를 완성합니다.
컴파일 및 저장: 두 블루프린트(BP_Door와 BP_GameManager)를 모두 컴파일하고 저장합니다.
- 언리얼 엔진 메인 에디터로 돌아와
BP_Door액터와BP_GameManager액터를 월드에 배치합니다. - 게임을 플레이하고
BP_Door액터의 문이 열리도록 상호작용합니다. (예:BP_Door의Interact인터페이스를 구현하고 플레이어 캐릭터에서E키를 눌렀을 때Interact메시지를 보내도록 설정) - 문이 열리는 순간,
BP_GameManager블루프린트에 바인드된 커스텀 이벤트가 실행되어 게임 매니저: 문이 열렸습니다! 메시지가 출력되는 것을 확인할 수 있습니다.
이벤트 디스패처의 장점
- 느슨한 결합(Loose Coupling): 신호를 보내는 액터(문)는 신호를 받는 액터(게임 매니저)가 누구인지, 어떤 타입인지 전혀 알 필요가 없습니다. 그저 신호를 보낼 뿐입니다.
- 유연성: 하나의 디스패처에 여러 개의 다른 블루프린트가 바인드될 수 있습니다. (예: 문이 열릴 때 게임 매니저도 알고, 사운드 매니저도 알고, 이펙트 매니저도 아는 등)
- 확장성: 나중에 새로운 액터가 문이 열리는 이벤트를 듣고 싶으면, 해당 액터에서
Bind Event노드만 추가하면 됩니다. 기존 문 블루프린트를 수정할 필요가 없습니다.
이벤트 디스패처는 복잡한 게임 시스템에서 블루프린트 간의 통신을 관리하는 데 매우 강력하고 유연한 방법입니다. 특히, 특정 사건 발생 시 여러 대상에게 알림이 필요한 경우에 최적의 솔루션입니다.
이번 절에서는 이벤트 디스패처의 기본 개념과 생성, 호출, 바인드 방법에 대해 알아보았습니다. 직접 참조의 한계를 극복하고 블루프린트 간의 느슨한 결합을 구현하는 중요한 통신 기법입니다.