관리 메뉴

기억을 위한 기록들

[UE4-CPP] 델리게이트(delegate)란? 본문

UnrealEngine/UE4 - CPP

[UE4-CPP] 델리게이트(delegate)란?

에드윈H 2021. 3. 7. 20:32

델리게이트(delegate)라는 단어를 사전에서 검색해보면 집단의 의사를 대표하는 대표자라고 나온다.

 

 

https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EB%8D%B8%EB%A6%AC%EA%B2%8C%EC%9D%B4%ED%8A%B8

 

하지만 컴퓨터 프로그래밍에서 델리게이트는 함수를 안전하게 호출할 수 있는 기능을 의미한다. (먹는 사과도 애플이고 아이폰 만드는 회사도 애플인 그런 느낌...?)

 

사실 C++ 언어에서는 델리게이트라는 개념이 존재하지 않는다.

델리게이트는 C++ 의 다음 세대 언어인 C#에서 ( 정확히는 CLI 플랫폼 기반 ) 선보인 개념으로, 콜백 함수를 등록하기 위해 C 혹은 C++에서 사용한 함수 포인터가 문법이 복잡하고, 위험한 방식이었다면, 델리게이트는 간편한 문법과 안전성을 갖춰 콜백 함수를 호출하기 위해 고안.

 

델리게이트의 간편함과 안정성 외에도 이전 방식과 다른 큰 특징은 사전적 의미대로 집단의 의사를 대표한다는 점입니다. 이는 딜리게이트가 하나의 함수 뿐만 아니라 동일한 리턴값과 인자 타입을 가지는 여러 개를 관리할 수 있다는 것을 의미.

 

델리게이트의 특징

델리게이트의 이러한 특징은 C# 언어의 주요 패턴 중 하나인 발행/구독(Publish/Subscribe) 패턴의 구현으로 이어집니다. C#의 발행/구독 패턴은 우리가 일상 생활에서 흔히 접하는 신문을 구독하는 절차와 유사한 방식.

 

구독자가 신문사에게 신문을 받아보겠다는 구독 의사를 밝히고 등록하면, 신문이 발행될 때마다 동일한 시간에 구독한 모든 구독자의 집으로 신문을 배달해주듯이, 특정 이벤트가 발생하면 딜리게이트에 등록된 모든 함수를 한꺼번에 호출가능.

 

게임에서의 예

1. 어떤 게임에서 보스 A 라는 몬스터와  A가 스폰한 미니언(Minion) B 3마리가 있어서 A가 죽으면, 이 B들도 함께 죽게 만들고 싶다고 가정할 때. 보스가 죽는 이벤트를 딜리게이트로 정의하고 미니언을 스폰할 때마다 각 미니언들이 이를 구독하게 설정해두면, 보스 A가 죽을 때 명령 하나로 모든 미니언 B들에게 A가 죽었다고 알려줄 수 있습니다. 그리고 알림을 받으면 B들도 다 죽게 만들면 된다.

 

2. 어떤 애니메이션 동작이 시작하고 끝날때 계속 동작중인지 체크하는 방식보다 애니메이션 재생이 끝났다고 폰(캐릭터)에게 끝났다고 알려주는 방식이 더 낫다.

 

서론이 길었는데, 딜리게이트 기능의 특징은 다음과 같이 요약할 수 있습니다.

- 함수 포인터의 직접 접근이 아닌 대리자를 통한 함수 호출 방식 

- 호출할 함수나 이를 포함하는 객체가 없어져도 대리자가 체크해 안전하게 처리할 수 있음. 

- 동일한 형을 가진 함수 여러 개를 대리자가 묶어서 관리하고, 필요할 때 동시에 모두 호출하는 것이 가능함.

 

앞서서도 말씀드렸듯이 딜리게이트 기능은 C++언어에서는 제공하지 않습니다만 우리의 언리얼 C++은 자체적으로 프레임웍을 제작해 이 기능을 지원하고 있습니다.

 

언리얼에서 델리게이트

2가지로 나누어진다.

1. C++객체에만 사용할수 있는 델리게이트

2. C++,블루프린트 객체가 모두 사용할 수 있는 델리게이트

 

블루프린트 오브젝트는 멤버 함수에 대한 정보를 저장하고 로딩하는 직렬화(Serialization) 매커니즘이 들어있기 때문에, 일반 C++언어가 관리하는 방법으로 멤버 함수를 관리 할 수 없다.

 

그래서 블루프린트와 관련된 C++함수는 모두 UFUNCTION 매크로를 사용해야한다.

이렇게 블루프린트 객체와도 연동하는 델리게이트를 언리얼엔진에서는 다이나믹 델릭게이트(Dynamic Delegate)라고한다.

 

 

사용 예)

1. 특정 애니메이션 몽타주가 끝나는것을 캐릭터클래스에게 알려준다.

캐릭터 클래스에서 PostInitializePostInitializeComponents에서 해당 함수를 애님 인스턴스의 OnMontageEnded 델리게이트에 바인딩한다.

OnMontageEnded 에 바인딩할 함수 

해당 모션 재생여부를 확인할 bool 변수

 

그리고 이제 구현부에서 아까 PostInitializePostInitializeComponents함수 안에

몽타주 재생이 끝나는 OnMontageEnded에 위에서 선언한 함수 OnRollMontageEnd를 바인딩 해준다.

그리고 특정 키를 누르면 RollOver함수가 동작되고 bIsRolling변수가 false라면 애님인스턴스에서 미리 지정 해준, Roll몽타주를 재생한다.

 

그리고 몽타주가 끝나면 바인딩된 OnRollMontageEnd함수가 동작한다.

 

 

OnMontageEnded 델리게이트는 블루프린트와 호환되는 성질외에도 여러개의 함수를 받을 수 있어서 행동이 끝나면 등록된 모든 함수들에게 모두 알려주는 기능도 제공. 이러한 델리게이트를 멀티캐스트 델리게이트(Muilticast Delegate)라고한다.

 

 

 

언리얼에서 델리게이트 기능을 사용하려면 먼저 매크로를 사용해 델리게이트를 선언해야 합니다. 델리게이트는 모든 함수 유형을 대변할 수 없고, 우리가 지정한 함수의 리턴값과 인자 타입을 가지는 함수만 대표할 수 있습니다.

 

 

델리게이트를 바인딩할 시 주의할 점은 델리게이트에 등록할 함수의 종류에 따라 호출하는 함수가 달라진다는 점입니다. 

언리얼 델리게이트 시스템에 등록 가능한 함수는 다음과 같습니다.

 

  • 전역 C++ 함수 : BindStatic API를 사용해 등록
  • 전역 C++ 람다 함수 : BindLambda API를 사용해 등록
  • C++클래스 멤버 함수 : BindRaw  API를 사용해 등록
  • 공유포인터 클래스의 멤버 함수 (쓰레드 미지원) : BindSP API를 사용해 등록 
  • 공유포인터 클래스의 멤버 함수 (쓰레드 지원) : BindThreadSafeSP API를 사용해 등록
  • UFUNCTION 멤버 함수 : BindUFunction API를 사용해 등록
  • 언리얼 오브젝트의 멤버함수 : BindUObject API를 사용해 등록

BindUFunction  사용 예

 

우선 파라미터 없는 기본 델리게이트를 FCustom이라는 이름으로 선언했다.(이름앞에 F를 안붙이면 에러뜸)

 

그리고 해당 델리게이트를 사용할 변수를 myDelegate 변수와 

델리게이트를 실행하면 바인딩되는 함수 CallDelegate() 함수도 같이 선언해주었다.

 

 

 

 

 

그 다음 여기서는 BeginPlay()에서 해당 변수 myDelegate변수에 CallDelegate 함수를 바인딩 시켜주었다.

그리고 IsBound()함수로 바인딩 되었다면 해당 변수를 실행시켜주는 함수 Execute(); 를 작성했다.

해당 바인딩 함수를 실행하면 아래와 같이 출력될것이다.

그리고 이제 게임을 실행 해보면,

 

BeginPlay 로그가 찍히면서, 바인딩함수안에 있는 Call Delegate!가 찍히는걸 볼 수 있다.

 

이렇게 한개와 바인드 해주는것을 싱글캐스트라고 하며, 두개이상씩 바인드 해주는게 멀티 캐스트이다.

 

싱글캐스트는 

델리게이트변수.BindUFunction(this,FName("함수명"); 이런식으로 Bind 해주는데, 

 

멀티캐스트는

델리게이트변수.AddUFunction(this,FName("함수명2"); 

델리게이트변수.AddUFunction(this,FName("함수명3"); Bind가 아니라 Add 해주고 있다.

 

그리고 다이나믹캐스트는 블루프린트와도 연동이 가능하다.

 

https://darkcatgame.tistory.com/66

 

정리하자면, 

- 딜리게이트는 함수 포인터 대신 간편한 문법으로 안전하게 호출해주는 대리자 개념. 콜백, 이벤트 구독에 많이 사용됨.

- 하나의 딜리게이트가 모든 유형의 함수를 커버할 수 없기 때문에 대리할 함수 유형을 매크로로 지정해야 한다.

- 언리얼 엔진의 입력 시스템은 딜리게이트를 통한 입력 값의 전달 방식으로 이루어져있다.  

- 연결(바인딩)할 함수의 성격에 따라 다양한 API가 존재한다. 

- 딜리게이트형선언::Create~ 함수를 사용해 즉석에서 딜리게이트를 제작해 넘겨주는 것도 가능하다. 

- 같은 유형을 가진 여러 함수를 묶어서 발행/구독 모델처럼 사용할 때는 MULTICAST 계열 매크로를 사용한다.

- 블루프린트와 연동시에는 DYNAMIC_MULTICAST 계열 매크로를 사용한다.

 

 

 

 

 

참고 자료 :

blog.naver.com/destiny9720/220945441201

 

[1-11] 언리얼 C++ 딜리게이트

안녕하세요 여러분~ 이번 시간에는 언리얼 C++의 특징인 딜리게이트(Delegate)에 대해 알아보겠습니다.딜...

blog.naver.com

 

docs.unrealengine.com/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Delegates/index.html

 

델리게이트

C++ 오브젝트 상의 멤버 함수를 가리키고 실행시키는 데이터 유형입니다.

docs.unrealengine.com

darkcatgame.tistory.com/66

 

UE4 C++ Delegate 정리 & 샘플 프로젝트

개인적으로 UE4 C++에서 Delegate를 사용할 때 처음에 굉장히 에러를 많이 겪었습니다, 그래서 이번 포스팅은 UE4 C++에서 Delegate를 사용하는 방법에 대해 정리하고 샘플프로젝트도 만들었습니다. https

darkcatgame.tistory.com