C++ 델리게이트 시스템 직접 구현: 게임 엔진 이벤트 구조 만들기

📚 델리게이트 시리즈

1편: 함수 포인터
2편: std::function
3편: Delegate 구현
4편: 엔진 스타일 Delegate

🚀 들어가며

이전 글에서는 std::function과 람다를 이용해
👉 유연한 콜백 구조를 만드는 방법을 살펴봤습니다.

std::function<void()> func = []()
{
    std::cout << "Hello\n";
};

func();

이 구조만으로도 충분히 강력합니다.

하지만 게임 엔진에서는 여기서 한 단계 더 나아갑니다.

❓ “하나의 이벤트에 여러 함수를 연결할 수는 없을까?”

예를 들어:

버튼 클릭
→ 사운드 재생
→ UI 업데이트
→ 로그 출력

👉 하나의 이벤트에 여러 동작이 연결됩니다.

이걸 가능하게 만드는 구조가 바로 델리게이트(Delegate)입니다.


🎯 델리게이트란 무엇인가?

델리게이트는 간단히 말하면:

  • 여러 개의 콜백 함수를 저장하고, 한 번에 실행하는 구조입니다.

🧠 기본 아이디어

이벤트 발생
↓
등록된 함수 리스트 순회
↓
모든 함수 실행

🎮 단순한 구현

먼저 아주 단순한 구조부터 만들어보겠습니다.

#include <vector>
#include <functional>

class Delegate
{
public:
    void Add(std::function<void()> func)
    {
        functions.push_back(func);
    }

    void Broadcast()
    {
        for (auto& func : functions)
        {
            func();
        }
    }

private:
    std::vector<std::function<void()>> functions;
};

🎯 사용 예제

#include <iostream>

void PlaySound()
{
    std::cout << "Play Sound\n";
}

void UpdateUI()
{
    std::cout << "Update UI\n";
}
Delegate onClick;

onClick.Add(PlaySound);
onClick.Add(UpdateUI);

onClick.Broadcast();

👉 출력:

Play Sound
Update UI

🔥 핵심 포인트

여러 개의 함수를 등록한다
↓
한 번에 실행한다

👉 이것이 델리게이트의 본질입니다.


🎯 람다와 함께 사용하기

onClick.Add([]()
{
    std::cout << "Log Event\n";
});

👉 이제 함수뿐 아니라 람다도 등록 가능합니다.


🎮 객체와 함께 사용하기

class Player
{
public:
    void OnClick()
    {
        std::cout << "Player Click\n";
    }
};
Player player;

onClick.Add([&player]()
{
    player.OnClick();
});

👉 결과:

Player Click

🧠 이 구조의 의미

이제 이벤트 시스템을 이렇게 표현할 수 있습니다.

이벤트
↓
리스너 등록
↓
이벤트 발생 시 호출

👉 완전한 이벤트 시스템 구조입니다.


⚠️ 문제점 1: 제거(Remove)가 없다

현재 구조는 추가만 가능합니다.

onClick.Add(func);

👉 하지만 제거는 불가능합니다.


🔧 간단한 Remove 구현

델리게이트에 추가된 함수 포인터 전체 제거는 쉽게 처리할 수 있습니다.

void Clear()
{
    functions.clear();
}

하지만, 특정 함수 제거는 더 복잡합니다.
이를 위해 실제 엔진에서는 ID 기반으로 관리합니다.


⚠️ 문제점 2: 성능

std::function는 함수 포인터보다 유연하지만 추가 비용이 발생

👉 이유:

  • 타입 소거
  • 내부 힙 할당 가능성

🎯 그래서 엔진에서는?

게임 엔진에서는 보통:

✔ 빠른 호출
✔ 타입 안전성
✔ 다양한 바인딩 방식

👉 이걸 위해 직접 델리게이트 시스템을 구현합니다


🔥 싱글 캐스트 vs 멀티 캐스트

지금 만든 것은:

👉 멀티 캐스트 델리게이트


✔ 싱글 캐스트

함수 1개만 저장

✔ 멀티 캐스트

함수 여러 개 저장

👉 지금 구현한 구조


🎮 엔진에서의 실제 사용

게임 엔진에서는 이런 구조로 사용됩니다.

키 입력
→ 여러 시스템 반응

충돌 발생
→ 여러 컴포넌트 반응

UI 이벤트
→ 여러 리스너 실행

🎯 구조 정리

함수 포인터
↓
std::function
↓
Delegate
↓
이벤트 시스템

🔥 핵심 정리

  • 델리게이트는 여러 콜백을 저장하는 구조이다.
  • Broadcast를 통해 모든 함수를 실행한다.
  • 람다와 함께 사용하면 매우 유연하다.
  • 이벤트 시스템의 핵심 구조다.

🎯 다음 단계

다음 단계에서는:

👉 엔진 스타일 델리게이트로 확장

  • 함수 등록 ID
  • 제거 기능
  • 성능 개선
  • 템플릿 기반 구조

👉 실제 엔진 수준으로 확장해보겠습니다.


🎮 마무리

델리게이트는 단순한 자료구조가 아니라
👉 게임 엔진의 이벤트 시스템 그 자체입니다.

이 구조를 이해하면:

  • 입력 시스템
  • UI 이벤트
  • 게임 로직 연결

👉 모두 하나의 흐름으로 보이기 시작합니다.


🚀 한 단계 더 나아가고 싶다면

델리게이트 구조는
입력 시스템, 이벤트 처리, 객체 구조와 깊게 연결됩니다.

👉 게임 엔진 구조를 더 깊이 이해하고 싶다면

아래 강의를 통해 직접 구현해보는 것을 추천드립니다.

C++로 만드는 게임 엔진 프레임워크 강의

👉 C++로 만드는 게임 엔진 프레임워크 강의 바로가기

단순히 사용하는 것을 넘어서,
엔진이 어떻게 동작하는지 이해하는 데 초점을 맞춘 내용입니다.

//
   

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다