icon
4장 : 블루프린트 통신 기법

블루프린트 인터페이스를 통한 통신


이전 절에서 이벤트 디스패처를 통해 블루프린트 간의 느슨한 결합을 구현하는 방법을 알아보았습니다. 이번 절에서는 3장에서 잠시 소개했던 블루프린트 인터페이스(Blueprint Interface) 가 어떻게 블루프린트 통신에 활용되는지, 그리고 이것이 직접 참조나 이벤트 디스패처와 비교했을 때 어떤 장점을 가지는지 더 깊이 있게 살펴보겠습니다. 인터페이스는 특히 다형성(Polymorphism) 을 활용한 유연한 통신에 매우 강력한 도구입니다.


블루프린트 인터페이스를 통한 통신이란?

블루프린트 인터페이스를 이용한 통신은 특정 기능의 '계약' 을 기반으로 합니다. 인터페이스는 어떤 클래스들이 구현해야 할 함수의 선언(Declaration) 만을 포함하며, 실제 구현(Definition) 은 각 클래스에 맡깁니다. 즉, "나는 이런 기능을 제공할 수 있다"는 약속을 하는 것이죠.

다른 블루프린트에서 이 인터페이스의 기능을 호출할 때는, 호출 대상이 실제로 이 인터페이스를 구현했는지 여부만 확인합니다. 구현했다면, 그 클래스가 어떻게 구현했는지와 상관없이 해당 인터페이스 함수를 호출할 수 있습니다. 이는 마치 어떤 스마트폰이든 충전기 규격만 맞으면 충전할 수 있는 것과 같습니다. 충전기는 어떤 브랜드의 폰인지 알 필요 없이, '충전 규격'만 지키면 됩니다.


인터페이스 통신 과정

블루프린트 인터페이스를 활용한 통신은 크게 세 단계로 이루어집니다.

블루프린트 인터페이스 정의: 통신에 사용될 함수(기능)를 인터페이스에 선언합니다. (3장 4절 복습)

  • 콘텐츠 브라우저에서 마우스 우클릭 > 블루프린트(Blueprints) > 블루프린트 인터페이스(Blueprint Interface) 선택. (예: BPI_Damageable)
  • 인터페이스 에디터에서 함수를 추가하고 입출력 핀을 정의합니다. (예: ApplyDamage 함수에 DamageAmount (Float) 입력 핀 추가)
  • 주의: 인터페이스 함수에는 로직을 구현하지 않습니다.

클래스에서 인터페이스 구현 및 함수 정의: 해당 기능을 제공할 블루프린트 클래스(예: BP_Enemy, BP_PlayerCharacter)에서 인터페이스를 '구현'하고, 인터페이스 함수를 '정의'합니다.

  • 인터페이스를 구현할 액터 블루프린트(예: BP_Enemy)를 엽니다.
  • 클래스 세팅(Class Settings) 을 클릭합니다.
  • 디테일 패널의 Implemented Interfaces 섹션에서 BPI_Damageable을 추가합니다.
  • 블루프린트를 컴파일하면 좌측 함수(Functions) 패널인터페이스 섹션에 ApplyDamage 함수가 나타납니다.
  • ApplyDamage 함수 위에서 마우스 우클릭 > 이벤트 구현(Implement Event)을 선택합니다.
  • 이벤트 그래프에 생성된 Event ApplyDamage 노드 뒤에 실제 대미지 처리 로직을 구현합니다. (예: CurrentHealth 변수에서 DamageAmount를 빼는 로직)
  • BP_PlayerCharacter에도 동일하게 BPI_Damageable 인터페이스를 구현하고 Event ApplyDamage 로직을 정의합니다.

인터페이스 메시지 호출: 다른 블루프린트(예: BP_Projectile - 발사체)에서 이 인터페이스 함수를 '메시지' 형태로 호출합니다.

  • BP_Projectile 블루프린트 에디터를 엽니다.
  • Projectile이 다른 액터와 충돌했을 때 대미지를 주고 싶다고 가정합니다.
  • Event Hit 노드 뒤에 Other Actor 출력 핀에서 드래그하여 Does Implement Interface 노드를 검색하여 연결합니다.
    • 이 노드는 연결된 액터 레퍼런스가 특정 인터페이스를 구현했는지 불리언 값을 반환합니다. Interface 핀에 BPI_Damageable을 선택합니다.
  • Does Implement InterfaceReturn Value 출력 핀을 Branch 노드의 Condition 핀에 연결합니다.
    • Branch 노드는 충돌한 액터가 BPI_Damageable 인터페이스를 구현했는지 여부에 따라 실행 흐름을 나눕니다.
  • Branch 노드의 True 출력 핀에서 드래그하여 ApplyDamage를 검색합니다. 이때, ApplyDamage (Message) 노드를 선택합니다.
    • Message 노드는 대상이 인터페이스를 구현했는지 자동으로 확인하고, 구현했을 경우 해당 인터페이스 함수를 호출해줍니다. Does Implement InterfaceBranch 노드를 사용하지 않고 바로 Message 노드를 연결해도 되지만, Does Implement Interface를 통해 명시적으로 확인하는 것이 안정성 확보에 도움이 됩니다.
  • ApplyDamage (Message) 노드의 Target 핀에는 Event HitOther Actor 핀을 연결합니다.
  • DamageAmount 입력 핀에는 발사체가 줄 대미지 값을 입력합니다. (예: 20.0)
  • 블루프린트를 컴파일하고 저장합니다.

인터페이스 통신의 장점

  • 강력한 다형성(Polymorphism): ApplyDamage (Message) 노드는 BP_EnemyBP_PlayerCharacter 모두에게 작동합니다. 발사체 블루프린트는 자신이 충돌한 대상이 '적'인지 '플레이어'인지 알 필요가 없습니다. 그저 '대미지를 받을 수 있는(BPI_Damageable 인터페이스를 구현한) 객체'라는 사실만 알면 됩니다. 이는 확장성을 극대화합니다.
  • 느슨한 결합(Loose Coupling): 호출하는 쪽(발사체)은 호출되는 쪽(적, 플레이어)의 구체적인 클래스 타입을 몰라도 됩니다. 오직 인터페이스만 알면 됩니다. 이는 나중에 새로운 BPI_Damageable을 구현하는 오브젝트(예: BP_DestructibleBox)가 추가되어도 발사체 블루프린트를 전혀 수정할 필요가 없다는 것을 의미합니다.
  • 유지보수 용이성: 특정 기능을 변경하고 싶다면, 해당 기능을 구현한 클래스만 수정하면 됩니다. 인터페이스 자체나 인터페이스를 호출하는 다른 블루프린트에는 영향을 주지 않습니다.
  • 명확한 계약: 인터페이스는 "이 기능을 구현하는 모든 클래스는 이 함수를 가져야 한다"는 명확한 계약을 제시합니다. 이는 팀 작업 시 각 클래스의 책임과 기능을 명확히 정의하는 데 큰 도움이 됩니다.

직접 참조, 이벤트 디스패처, 인터페이스 비교

특징직접 참조 (Direct Reference)이벤트 디스패처 (Event Dispatcher)블루프린트 인터페이스 (Blueprint Interface)
결합도강한 결합 (Tight Coupling)느슨한 결합 (Loose Coupling)느슨한 결합 (Loose Coupling)
통신 방향일대일 (정확한 대상 지정)일대다 (여러 대상에게 알림)다대다 (다양한 클래스에서 구현 가능, 다양한 클래스에서 호출 가능)
주요 용도특정 액터 인스턴스에 직접 접근, 변수 값 확인특정 사건 발생 시 여러 대상에게 알림특정 '능력'을 가진 객체에게 공통 명령 전달, 다형성 구현
안정성Access None 발생 가능성 높음 (유효성 검사 필수)바인드된 대상이 없으면 아무 일도 일어나지 않음대상이 인터페이스를 구현했는지 확인 필요
복잡도가장 간단중간중간 ~ 높음 (객체 지향 개념 이해 필요)

인터페이스는 특히 다형성을 기반으로 하는 설계에 가장 적합한 통신 기법입니다. 게임 내에 다양한 종류의 오브젝트들이 공통적인 특정 행동(예: 상호작용, 대미지 받기, 활성화/비활성화)을 해야 할 때, 인터페이스를 사용하면 매우 유연하고 확장 가능한 시스템을 구축할 수 있습니다.


이번 절에서는 블루프린트 인터페이스를 통한 통신 방법을 심도 있게 다루었습니다. 직접 참조, 이벤트 디스패처, 그리고 인터페이스는 각각 다른 상황과 요구사항에 적합한 통신 기법이므로, 각 방법의 장단점을 이해하고 적절하게 선택하여 사용하는 것이 중요합니다.