본문으로 건너뛰기

안동민 개발노트

본문 시작

이벤트 디스패처의 기본 사용법

이벤트 디스패처를 선언·바인딩·호출해 한 액터의 변화를 여러 수신자에게 느슨하게 전달하는 법을 익힙니다.

지난 절에서 다룬 직접 참조 통신은 간단하고 명확하지만, 호출 측이 대상 블루프린트의 구체 타입을 알아야 하는 강한 결합(Tight Coupling) 문제가 있습니다.

이 구조는 확장성과 유지보수성에 부담을 줄 수 있습니다.

이번 절에서는 이 문제를 줄이고 느슨한 결합(Loose Coupling)을 가능하게 하는 통신 기법, 이벤트 디스패처(Event Dispatcher)를 다룹니다.

Dispatcher 생성, Bind, Call, Unbind 관계도

Event Dispatcher는 소유자와 구독자를 느슨하게 연결하지만, 중복 바인딩과 해제를 관리하지 않으면 레벨 전환과 UI에서 문제가 생깁니다.

  1. Dispatcher 선언

    소유자 블루프린트에서 전달할 payload와 이벤트 이름을 명확히 정합니다. 계약

  2. 참조 확보

    구독자는 소유자 인스턴스 참조를 안전하게 얻은 뒤 Bind를 수행합니다. reference

  3. Bind Event

    구독자의 Custom Event를 연결해 소유자 이벤트에 반응하게 합니다. subscribe

  4. Call Dispatcher

    상태 변경 시 소유자가 Dispatcher를 호출해 구독자들에게 알립니다. publish

  5. Unbind

    UI 닫힘, 액터 파괴, 레벨 전환 시 바인딩을 해제합니다. cleanup


이벤트 디스패처란 무엇인가?

이벤트 디스패처는 특정 이벤트가 발생했음을 알리는 신호기와 같습니다.

그리고 이 신호를 듣고 싶은 블루프린트들은 이 신호기에 자신을 등록(Bind) 해두고, 신호가 발생했을 때 자신이 할 일을 지정(Assign) 해둡니다.

즉, 이벤트 디스패처는 “어떤 일이 일어났을 때 알려주겠다”는 신호를 보냅니다.

수신자는 이 신호를 받기 위해 미리 등록합니다.

이 방식은 직접 참조와 달리, 신호를 보내는 쪽(디스패처를 호출하는 쪽)이 신호를 받는 쪽(디스패처에 등록한 쪽)이 누구인지, 어떤 타입인지 전혀 알 필요가 없게 만듭니다.

그저 특정 신호를 발생시킨다는 사실만 알면 됩니다.

이벤트 디스패처의 핵심 개념
  • 생성 (Create): 이벤트를 알릴 디스패처를 정의합니다.
  • 바인드 (Bind): 특정 블루프린트가 디스패처에 나는 이 신호를 들을 준비가 되었어라고 등록합니다.
  • 호출 (Call / Dispatch): 디스패처를 소유한 블루프린트가 신호를 발생시킨다는 의미로 디스패처를 호출합니다.
  • 언바인드 (Unbind): 더 이상 신호를 듣고 싶지 않을 때 등록을 해제합니다.
Dispatcher 호출 흐름

발신자는 디스패처를 호출할 뿐이고, 수신자는 미리 등록한 이벤트로 각자 반응합니다.

  1. 1
    느슨한 결합

    BP_Door는 UI, 사운드, 퀘스트 시스템의 구체 타입을 몰라도 됩니다.

  2. 2
    Create

    BP_Door 안에 OnDoorOpened 디스패처를 정의합니다.

  3. 3
    Bind

    듣고 싶은 Blueprint가 실행할 Custom Event를 등록합니다.

  4. 4
    Call

    문이 열리는 순간 디스패처가 모든 등록자에게 알립니다.

  5. 5
    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)하기

Event Dispatcher 발행-구독 흐름

디스패처를 가진 Blueprint는 사건이 일어났다고 알리고, 관심 있는 다른 Blueprint는 미리 Bind해 두었다가 신호를 받아 자기 로직을 실행합니다.

  1. 1
    publisher

    BP_Door가 OnDoorOpened 정의

  2. 2
    bind

    GameManager가 BeginPlay에서 등록

  3. 3
    call

    문이 열릴 때 dispatcher 호출

  4. 4
    subscriber

    등록된 Custom Event들이 실행

이제 다른 블루프린트(예: BP_PlayerCharacter 또는 BP_GameManager)가 BP_DoorOnDoorOpened 이벤트를 듣고 반응하도록 바인드해봅시다.

듣고 싶은 블루프린트 열기: 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_DoorBP_GameManager)를 모두 컴파일하고 저장합니다.

테스트
  • 언리얼 엔진 메인 에디터로 돌아와 BP_Door 액터와 BP_GameManager 액터를 월드에 배치합니다.
  • 게임을 플레이하고 BP_Door 액터의 문이 열리도록 상호작용합니다. (예: BP_DoorInteract 인터페이스를 구현하고 플레이어 캐릭터에서 E 키를 눌렀을 때 Interact 메시지를 보내도록 설정)
  • 문이 열리는 순간, BP_GameManager 블루프린트에 바인드된 커스텀 이벤트가 실행되어 게임 매니저: 문이 열렸습니다! 메시지가 출력되는 것을 확인할 수 있습니다.

이벤트 디스패처의 장점

  • 느슨한 결합(Loose Coupling): 신호를 보내는 액터(문)는 신호를 받는 액터(게임 매니저)가 누구인지, 어떤 타입인지 전혀 알 필요가 없습니다. 그저 신호를 보낼 뿐입니다.
  • 유연성: 하나의 디스패처에 여러 개의 다른 블루프린트가 바인드될 수 있습니다. (예: 문이 열릴 때 게임 매니저도 알고, 사운드 매니저도 알고, 이펙트 매니저도 아는 등)
  • 확장성: 나중에 새로운 액터가 문이 열리는 이벤트를 듣고 싶으면, 해당 액터에서 Bind Event 노드만 추가하면 됩니다. 기존 문 블루프린트를 수정할 필요가 없습니다.

디스패처를 사용할 때는 생성과 호출뿐 아니라 바인드한 수신자가 언제 해제되는지까지 함께 보면 흐름이 더 안정적입니다.

아래 다이어그램은 OnDoorOpened 신호가 발신자, 디스패처, 여러 리스너 사이를 지나가는 생명주기를 정리합니다.

디스패처는 호출보다 등록 수명이 중요하다

발신자는 신호만 보내고, 수신자는 자신이 언제 듣기 시작하고 언제 빠질지 관리해야 합니다.

발신자, 디스패처, 수신자 책임표
구간담당하는 일확인 기준
Bind BeginPlay 또는 활성화ListenerTarget 참조에 커스텀 이벤트를 등록IsValid 문 참조가 없으면 등록하지 않습니다.
Call 문이 열린 순간SenderOnDoorOpened와 필요한 입력값을 호출발신자는 누가 듣는지 몰라도 됩니다.
Handle 수신자 반응UI, Sound, Manager메시지, 사운드, 상태 갱신을 각자 처리역할 분리 한 수신자는 한 책임만 맡깁니다.
Unbind EndPlay 또는 비활성화Listener더 이상 듣지 않을 이벤트 연결을 제거잔류 방지 사라진 위젯과 타이머가 반응하지 않게 합니다.

이벤트 디스패처는 복잡한 게임 시스템에서 블루프린트 간의 통신을 관리하는 데 매우 강력하고 유연한 방법입니다.

특히, 특정 사건 발생 시 여러 대상에게 알림이 필요한 경우에 최적의 솔루션입니다.


이번 절에서는 이벤트 디스패처의 기본 개념과 생성, 호출, 바인드 방법에 대해 알아보았습니다.

직접 참조의 한계를 극복하고 블루프린트 간의 느슨한 결합을 구현하는 중요한 통신 기법입니다.

디스패처를 적용하기 전에는 사건의 성격, 리스너 수, 해제 시점을 함께 확인합니다.

디스패처는 호출자가 듣는 쪽을 몰라도 되는 신호입니다

문이 열렸다는 사실만 알리고, 반응할 블루프린트들은 각자 바인드한 이벤트를 실행하게 만듭니다.

  1. Create → Bind → Call

    Signal 디스패처를 만들고, 리스너가 등록한 뒤, 소유자가 신호를 호출합니다. Create 신호 이름과 필요한 입력 핀을 이벤트 디스패처에 선언합니다. Bind UI, 사운드, 퀘스트 블루프린트가 자신이 실행할 이벤트를 연결합니다. Call 문이 열린 뒤 Call 노드를 실행해 바인드된 이벤트를 모두 호출합니다. Unbind 더 이상 듣지 않을 객체는 언바인드해 의도치 않은 호출을 줄입니다.

  2. Create → Bind → Call

    Signal 디스패처를 만들고, 리스너가 등록한 뒤, 소유자가 신호를 호출합니다.

  3. OnDoorOpened 정의

    Create 신호 이름과 필요한 입력 핀을 이벤트 디스패처에 선언합니다.

  4. 관심 있는 쪽 등록

    Bind UI, 사운드, 퀘스트 블루프린트가 자신이 실행할 이벤트를 연결합니다.

  5. 발생 순간 알림

    Call 문이 열린 뒤 Call 노드를 실행해 바인드된 이벤트를 모두 호출합니다.

  6. 수명 종료 정리

    Unbind 더 이상 듣지 않을 객체는 언바인드해 의도치 않은 호출을 줄입니다.

이벤트 디스패처의 바인드와 호출 흐름을 점검하는 기준을 추가합니다.

이벤트 디스패처는 발행자와 청취자를 Bind와 Call로 분리한다

문은 OnDoorOpened를 Call만 하고, UI·사운드·퀘스트는 BeginPlay에서 Bind해 각자 반응한다.

  1. BP_Door

    문 열림 순간 Call OnDoorOpened만 실행

  2. UI Widget

    문 열림 표시 갱신

  3. Audio Actor

    효과음 재생

  4. Quest Manager

    목표 진행도 증가

역할의미
Bind청취자는 BeginPlay나 초기화 시점에 자신의 이벤트를 등록한다.
Call발행자는 사건이 일어난 순간 디스패처만 호출한다.
Unbind청취자가 사라질 수 있으면 EndPlay에서 연결을 정리한다.

이벤트 디스패처를 사용할 때는 사건을 알리는 블루프린트와 그 알림을 구독하는 블루프린트를 분리해 봅니다.

디스패처는 발행자와 여러 구독자의 연결 수명으로 읽는다

문이 열린 사건은 한 번 발생하지만 UI, 사운드, 퀘스트는 각자 BeginPlay에서 Bind해 따로 반응한다.

  1. BP_Door

    OnDoorOpened를 Call하는 발행자

  2. Event Dispatcher

    누가 듣는지 모르는 방송 지점

  3. UI Widget

    문 열림 표시 갱신

  4. Audio Actor

    효과음 재생

  5. Quest Manager

    목표 진행도 증가

역할의미
Bind구독자는 생성 시점에 자신의 이벤트를 등록한다.
Call발행자는 사건이 일어난 순간 디스패처만 호출한다.
Unbind사라질 수 있는 구독자는 EndPlay에서 연결을 정리한다.