OSWorlds - 게임 블로그 📌 게임 프로그래밍 📌 게임소식 🔑 로그인 📝 회원가입

언리얼 엔진 Blueprint Interface 사용법과 Cast와의 차이 총정리

언리얼 엔진에서 블루프린트를 만들다 보면 다른 Blueprint의 함수나 변수를 사용해야 하는 상황이 계속 발생합니다.

가장 먼저 배우는 방법은 보통 Cast To입니다. 플레이어가 적을 공격할 때 Cast To BP_EnemyBase, UI에서 플레이어 정보를 가져올 때 Cast To BP_PlayerCharacter처럼 사용하는 방식입니다.

저도 처음에는 Blueprint끼리 연결할 일이 생기면 대부분 Cast부터 사용했습니다. 간단한 프로젝트에서는 큰 문제가 없지만, 적 종류와 상호작용 가능한 Actor가 늘어나기 시작하면 Cast 노드가 계속 늘어나고 Blueprint끼리 강하게 연결되는 문제가 생깁니다.

이때 알아두면 좋은 기능이 바로 Blueprint Interface(BPI)​입니다.

💡 한 줄 정답 — Blueprint Interface는 서로 다른 Blueprint가 같은 함수 규칙을 공유하도록 만드는 통신 방법입니다. Cast가 “이 객체가 BP_EnemyBase인가?”를 확인하고 특정 클래스의 기능에 접근하는 방식이라면, Interface는 “이 객체가 이 기능을 지원하는가?”를 중심으로 통신하는 방식​이라고 이해하면 쉽습니다.

목차


Blueprint Interface란?

Blueprint Interface는 여러 Blueprint가 공통으로 사용할 함수의 형태를 정의하는 Blueprint 자산입니다.

예를 들어 게임에 다음 Actor가 있다고 해보겠습니다.

BP_Enemy
BP_Boss
BP_DestructibleBox
BP_TrainingDummy

플레이어 공격이 이 객체들에게 피해를 줄 수 있다고 가정하겠습니다.

Cast 중심으로 구현한다면 상황에 따라 다음과 같은 구조가 만들어질 수 있습니다.

Hit Actor
   ↓
Cast To BP_Enemy
   ↓ 실패
Cast To BP_Boss
   ↓ 실패
Cast To BP_DestructibleBox
   ↓ 실패
Cast To BP_TrainingDummy

객체 종류가 계속 늘어나면 Cast도 함께 늘어납니다.

Blueprint Interface를 사용하면 접근 방법을 바꿀 수 있습니다.

BPI_Damageable
       │
       └── ReceiveDamage
              ↑
     ┌────────┼────────┐
 BP_Enemy   BP_Boss   BP_Box

플레이어 입장에서는 대상이 Enemy인지 Boss인지 알 필요가 없습니다.

Hit Actor
    ↓
Receive Damage (Message)

만 호출하면 됩니다.

각 Blueprint가 BPI_Damageable을 구현하고 있다면 자신에게 맞는 방식으로 ReceiveDamage를 처리할 수 있습니다.

[언리얼 엔진 Blueprint Interface 기본 구조]


Cast와 Blueprint Interface의 차이

Blueprint Interface를 이해하려면 먼저 Cast와 무엇이 다른지 알아두는 것이 좋습니다.

구분CastBlueprint Interface
목적특정 클래스 확인 및 접근공통 기능 호출
클래스 의존성비교적 높음낮출 수 있음
대상 클래스 정보알아야 함몰라도 호출 가능
고유 변수 접근가능직접 접근 불가
여러 종류 Actor 처리구조가 복잡해질 수 있음유리함
구현 난이도쉬움처음에는 개념 필요
추천 상황특정 객체 직접 제어공통 행동 요청

예를 들어

CurrentEnemy → Cast To BP_Boss

라는 코드에는 이미

“이 Object를 BP_Boss로 사용하고 싶다.”

라는 의도가 들어 있습니다.

반면 Interface는

Interact (Message)

처럼 사용할 수 있습니다.

호출하는 쪽에서는 대상이 문인지 NPC인지 아이템인지 몰라도 됩니다.

Player
  ↓
Interact
  ↓
┌───────────┬──────────┬───────────┐
Door        NPC        Item
문 열기     대화하기    아이템 획득

같은 요청을 받더라도 실제 행동은 각 Blueprint가 결정합니다.

[언리얼 엔진 Cast와 Blueprint Interface 차이]


Blueprint Interface 만드는 방법

Blueprint Interface를 직접 만들어보겠습니다.

Content Browser의 빈 공간에서 마우스 오른쪽 버튼을 누른 후 Blueprint Interface를 생성합니다.

Content Browser
   ↓
Right Click
   ↓
Blueprints
   ↓
Blueprint Interface

이름은 알아보기 쉽게 만드는 것이 좋습니다.

예를 들어 상호작용 시스템이라면

BPI_Interactable

피해 처리 시스템이라면

BPI_Damageable

처럼 BPI_ 접두사를 사용하면 일반 Blueprint와 쉽게 구분할 수 있습니다.

이번 예제에서는

BPI_Damageable

을 만들고 다음 함수를 추가해보겠습니다.

ReceiveDamage

Input에는 다음과 같은 값을 전달할 수 있습니다.

DamageAmount : Float
Attacker : Actor
HitLocation : Vector

즉 공격하는 쪽에서는 단순히 “피해를 받아라”라고 요청하는 것이 아니라 필요한 데이터도 함께 전달할 수 있습니다.

ReceiveDamage
 ├─ DamageAmount
 ├─ Attacker
 └─ HitLocation

이렇게 만들어 놓으면 Enemy와 Boss 등 여러 Blueprint에서 같은 규칙을 사용할 수 있습니다.

[언리얼 엔진 Blueprint Interface 함수 생성 방법]


Interface를 Blueprint에 적용하는 방법

Interface를 만들었다고 자동으로 모든 Blueprint에서 사용할 수 있는 것은 아닙니다.

Interface 기능을 받을 Blueprint에 등록해야 합니다.

예를 들어 BP_EnemyBase를 열고 다음으로 이동합니다.

Class Settings
      ↓
Interfaces
      ↓
Implemented Interfaces
      ↓
Add
      ↓
BPI_Damageable

등록이 완료되면 My Blueprint 또는 Event Graph에서 Interface 관련 함수를 구현할 수 있습니다.

예를 들어 Enemy에서는 다음처럼 구성할 수 있습니다.

Event ReceiveDamage
       ↓
CurrentHealth - DamageAmount
       ↓
Set CurrentHealth
       ↓
Play Hit Animation

Boss에서도 동일한 Interface를 등록할 수 있습니다.

Event ReceiveDamage
       ↓
BossHealth - DamageAmount
       ↓
Set BossHealth
       ↓
Boss Hit Reaction

호출하는 Player 입장에서는 둘의 내부 로직을 알 필요가 없습니다.

둘 다 단순히

ReceiveDamage

라는 동일한 요청을 받는 구조입니다.


Interface Message 호출 방법

이제 Player가 적을 공격했다고 가정해보겠습니다.

Sphere Trace나 Line Trace를 이용했다면 Hit Result에서 다음 값을 얻을 수 있습니다.

Break Hit Result
      ↓
Hit Actor

이 Actor를 Interface Message의 Target으로 연결합니다.

Hit Actor
    ↓
ReceiveDamage (Message)

그리고 DamageAmount에 공격력을 전달합니다.

Attack Damage
      ↓
DamageAmount

전체 흐름을 단순화하면 다음과 같습니다.

Attack
  ↓
Sphere Trace
  ↓
Break Hit Result
  ↓
Hit Actor
  ↓
ReceiveDamage (Message)
  ↓
DamageAmount = 30

이제 공격 대상이 Interface를 구현했다면 해당 Blueprint의 ReceiveDamage 구현이 실행됩니다.

여기서 중요한 부분은 Message 방식의 Interface 호출은 대상이 해당 Interface를 구현하지 않은 경우 호출할 기능이 없다는 점입니다. 따라서 게임 로직상 반드시 Interface 구현 여부를 확인해야 하는 경우에는 Does Implement Interface 등을 이용해 분기하는 것도 좋은 방법입니다.

[Blueprint Interface Message로 다른 Actor 함수 호출하기]


전투 시스템에서 Interface 활용하기

Interface가 특히 유용한 분야가 전투 시스템입니다.

예를 들어 공격 가능한 대상이 다음처럼 늘어났다고 해보겠습니다.

일반 적
보스
훈련용 허수아비
파괴 가능한 오브젝트
특수 NPC

Cast 기반으로 각각 구분하기 시작하면 공격 Blueprint가 대상 종류를 너무 많이 알아야 합니다.

대신

BPI_Damageable

이라는 공통 규칙을 만들어 두면 공격 시스템은 다음 정도만 처리할 수 있습니다.

Hit Actor
    ↓
Does Implement Interface?
    ↓
       True
        ↓
ReceiveDamage

그리고 실제 피해 반응은 각 Actor가 담당합니다.

BP_Enemy
→ HP 감소 + Hit Montage

BP_Boss
→ Boss HP 감소 + 슈퍼아머 확인

BP_Box
→ 내구도 감소 + 파괴

BP_Dummy
→ Damage 숫자 표시

이 구조의 장점은 나중에 새로운 피해 대상이 추가되어도 플레이어의 공격 Blueprint를 계속 수정할 필요가 줄어든다는 것입니다.


상호작용 시스템에서 활용하기

Blueprint Interface의 대표적인 활용 사례가 상호작용 시스템입니다.

플레이어가 E키를 눌렀다고 가정하겠습니다.

E Key
 ↓
Line Trace
 ↓
Hit Actor
 ↓
Interact (Message)

그리고 여러 Actor가 BPI_Interactable을 구현합니다.

ActorInteract 실행 결과
BP_Door문 열기
BP_NPC대화 시작
BP_Item아이템 획득
BP_Chest상자 열기
BP_Switch스위치 작동

플레이어 Blueprint에는 다음과 같은 Cast가 필요하지 않습니다.

Cast To BP_Door
Cast To BP_NPC
Cast To BP_Item
Cast To BP_Chest

Player는 그냥

Interact

를 호출하고 각 Actor가 자신의 행동을 처리합니다.

프로젝트 규모가 커질수록 이런 구조의 장점이 커집니다.


Interface가 실행되지 않을 때 확인할 것

Blueprint Interface를 처음 사용하면 “노드는 실행됐는데 아무 일도 일어나지 않는다”는 문제를 만나기 쉽습니다.

이때는 다음 순서로 확인해보는 것이 좋습니다.

1. Target이 올바른가?

ReceiveDamage
Target = ?

Message를 받을 실제 Actor Reference가 Target에 들어가야 합니다.

2. 해당 Blueprint에 Interface를 등록했는가?

Class Settings
→ Implemented Interfaces

에서 확인합니다.

3. Interface Event를 실제로 구현했는가?

Interface만 등록하고 Event ReceiveDamage 내부 로직을 만들지 않았다면 원하는 결과가 나오지 않습니다.

4. Hit Actor가 생각한 Actor가 맞는가?

Print String을 이용해

Hit Actor
 ↓
Get Display Name
 ↓
Print String

으로 실제 충돌 Actor를 확인해보는 것도 좋습니다.

5. Does Implement Interface로 확인

디버깅할 때는 다음 구조도 유용합니다.

Hit Actor
    ↓
Does Implement Interface
    ↓
Branch
 ┌──────┴──────┐
True          False
 ↓              ↓
Interact      Print String

이렇게 만들면 Interface가 등록되지 않은 객체를 빠르게 확인할 수 있습니다.


Cast를 사용해야 하는 경우

Interface가 편리하다고 해서 Cast를 모두 없애야 하는 것은 아닙니다.

특정 Blueprint만 가지고 있는 기능이나 변수에 접근해야 한다면 Cast가 훨씬 자연스러울 수 있습니다.

예를 들어

BP_Boss

만 가지고 있는

BossPhase
EnrageMode
StartBossPattern

에 접근해야 한다면

Actor Reference
      ↓
Cast To BP_Boss
      ↓
StartBossPattern

같은 구조가 적절할 수 있습니다.

제가 구분하는 기준은 비교적 단순합니다.

"너 BP_Boss 맞아?"
→ Cast

"너 Damage 받을 수 있어?"
→ Interface

이렇게 생각하면 두 기능의 역할을 구분하기 쉽습니다.


Blueprint Interface 설계 시 주의점

Interface 역시 무조건 많이 만든다고 좋은 것은 아닙니다.

다음과 같이 지나치게 세분화하면

BPI_OpenDoor
BPI_CloseDoor
BPI_OpenChest
BPI_PickupItem
BPI_TalkNPC

오히려 관리해야 하는 Interface만 많아질 수 있습니다.

기능의 의미를 기준으로

BPI_Interactable

처럼 묶고

Interact
CanInteract

등의 공통 기능을 구성하는 것이 더 관리하기 쉬운 경우가 많습니다.

또한 Interface는 Reference가 필요 없다는 의미가 아닙니다.

Interface Message 역시 결국

Target

이 필요합니다.

즉,

Hit Actor → Interface Message

처럼 어떤 Object에게 메시지를 보낼 것인지는 알고 있어야 합니다.

이 부분은 이전에 살펴본 Accessed None 문제와도 연결되는 중요한 개념입니다.


마무리

Blueprint Interface는 언리얼 엔진 프로젝트가 커지기 시작할 때 상당히 유용한 Blueprint 통신 방법입니다.

Cast가 잘못된 기능인 것은 아닙니다. 문제는 모든 Blueprint 통신을 Cast 하나로 해결하려고 할 때입니다.

다음 기준만 기억해도 좋습니다.

특정 Class의 기능이 필요하다
→ Cast

서로 다른 Actor에게 동일한 행동을 요청한다
→ Blueprint Interface

하나의 이벤트를 여러 객체에 알려야 한다
→ Event Dispatcher

특히 전투 시스템에서는 BPI_Damageable, 상호작용 시스템에서는 BPI_Interactable 같은 Interface를 만들어두면 새로운 적이나 오브젝트를 추가할 때 기존 Player Blueprint를 계속 수정해야 하는 상황을 줄일 수 있습니다.

Blueprint Interface까지 이해했다면 다음으로 Event Dispatcher를 공부해보는 것을 추천합니다. Interface가 “특정 객체에게 공통 기능을 요청하는 방법”이라면 Event Dispatcher는 하나의 이벤트 발생 사실을 다른 Blueprint들에게 전달하는 구조를 이해하는 데 도움이 됩니다.


참고 사이트

최신 사용법과 세부 동작은 Epic Games의 Unreal Engine 공식 문서를 함께 확인하는 것을 추천합니다.


함께 보면 좋은 글

  1. 언리얼 엔진 Accessed None 오류 원인과 해결 방법
    • 추천 위치: Interface가 실행되지 않을 때 확인할 것
  2. 언리얼 엔진 Event Dispatcher 사용법과 활용 방법
    • 추천 위치: 글 마지막
  3. 언리얼 엔진 Actor, Pawn, Character 차이 총정리
    • 추천 위치: Blueprint Interface란?
  4. 언리얼 엔진 PlayerController 역할과 Possess 이해하기
    • 추천 위치: 상호작용 시스템에서 활용하기
  5. 언리얼 엔진 Blueprint와 C++ 차이 및 학습 순서
    • 추천 위치: 마무리

댓글 달기

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

위로 스크롤