직접 참조를 통한 블루프린트 통신
대상 액터 참조를 얻어 변수와 함수를 직접 호출하고 캐스트·수명 관리·결합도 측면의 장단점을 판단합니다.
블루프린트로 게임을 개발하다 보면, 서로 다른 블루프린트들이 정보를 주고받거나 특정 기능을 호출해야 하는 경우가 빈번하게 발생합니다.
예를 들어, 플레이어 캐릭터 블루프린트가 문 블루프린트에게 열려라는 명령을 내리거나, 폭발 블루프린트가 주변의 모든 적 블루프린트에게 대미지를 받아라는 신호를 보내는 것과 같습니다.
이처럼 블루프린트 간에 상호작용하는 방법을 블루프린트 통신(Blueprint Communication)이라고 합니다.
이번 절에서는 가장 기본적인 블루프린트 통신 방법인 직접 참조(Direct Reference)를 통한 통신에 대해 알아보겠습니다.
블루프린트가 이미 어떤 액터를 다룰지 알고 있다면 Object Reference 변수에 담아 함수와 값을 직접 호출한다.
- 대상 선택
Actor 맵에 배치된 문, 적, UI처럼 호출 대상이 하나로 특정된다.
- 참조 변수
Object Reference 변수 타입을 대상 블루프린트로 지정해 참조를 저장한다.
- 할당 시점
Expose / Get 에디터 지정, BeginPlay 검색, Overlap 이벤트로 실제 인스턴스를 넣는다.
- 호출
Call Function 참조에서 함수나 변수를 꺼내 열기, 데미지 적용 같은 동작을 실행한다.
| 판단 | 직접 참조가 맞는 경우 | 다른 통신이 나은 경우 |
|---|---|---|
| 대상 수 | 문 하나, 보스 하나처럼 대상이 명확하다. | 대상이 많거나 런타임에 자주 바뀐다. |
| 유효성 | 호출 전 Is Valid 로 생존 여부를 본다. | 스폰/파괴가 잦아 참조가 쉽게 끊긴다. |
| 결합도 | 두 블루프린트가 서로를 알아도 설계가 단순하다. | 인터페이스나 이벤트 디스패처가 더 느슨하다. |
직접 참조란 무엇인가?
직접 참조는 특정 블루프린트가 다른 특정 블루프린트 인스턴스에 대한 직접적인 연결(포인터)을 가지는 것을 의미합니다.
마치 여러분이 친구의 집 주소를 정확히 알고 찾아가는 것과 같습니다.
주소를 알면 그 친구의 집을 직접 방문하여 원하는 요청을 할 수 있죠.
언리얼 엔진에서 직접 참조는 주로 변수(Variable)를 통해 이루어집니다.
어떤 블루프린트가 다른 블루프린트 타입의 변수를 가지면, 그 변수에 특정 블루프린트 인스턴스를 할당하여 직접적인 연결을 만들 수 있습니다.
직접 참조를 통한 통신 과정
가장 단순한 통신 방식이지만 참조를 어디서 얻고 언제 비어 있을 수 있는지 표시해야 Access None을 피한다.
- Reference Variable
TargetDoor: BP_Door 타입 선언
- Assign Target
Details, BeginPlay, Overlap 값 할당
- IsValid
None인지 검사 분기
- Call Function
OpenDoor / Set 변수 대상 호출
- Handle None
실패 메시지 또는 무시 안전 경로
| 점검 | 기준 |
|---|---|
| 수동 할당 | 레벨에 배치된 특정 인스턴스를 Details에서 연결한다. |
| 동적 할당 | BeginPlay 탐색이나 Overlap 결과로 참조를 채운다. |
| 검수 | 호출 전 IsValid와 실패 경로가 보이면 직접 참조가 안전해진다. |
직접 참조를 이용한 블루프린트 통신은 다음과 같은 단계로 이루어집니다.
- 통신을 시작할 블루프린트(예:
BP_PlayerCharacter)를 엽니다. - 변수 패널에서 새 변수를 추가합니다.
- 변수 유형(Variable Type)을 참조하고 싶은 블루프린트 클래스(예:
BP_Door타입의Object Reference)로 설정합니다. 이렇게 하면 이 변수는BP_Door타입의 액터 인스턴스를 담을 수 있게 됩니다. 변수 이름은TargetDoor와 같이 설정할 수 있습니다.
참조할 인스턴스에 변수 값 할당 이것이 직접 참조 통신에서 가장 중요한 단계입니다.
변수를 만들었다고 해서 자동으로 연결되는 것이 아니라, 특정 월드에 존재하는 액터 인스턴스를 그 변수에 할당해주어야 합니다.
할당하는 방법은 여러 가지가 있습니다.
-
수동 할당 (디테일 패널)
BP_PlayerCharacter블루프린트 에디터에서TargetDoor변수를 선택합니다.디테일 패널에서
인스턴스 편집 가능(Instance Editable)옵션을 체크합니다. (또는 눈 아이콘을 클릭하여 열린 눈 형태로 만듭니다.) 이렇게 하면 이 변수가 월드에 배치된BP_PlayerCharacter인스턴스에서 직접 편집 가능해집니다.메인 언리얼 에디터로 돌아와 월드에 배치된
BP_PlayerCharacter액터를 선택합니다.디테일 패널을 살펴보면
TargetDoor변수가 보일 것입니다.이 변수 옆의 드롭다운을 클릭하거나, 스포이드 아이콘을 클릭하여 월드에 배치된 특정
BP_Door액터 인스턴스를 직접 선택하거나, 월드 아웃라이너에서 해당 액터를 드래그하여 변수 칸에 놓을 수 있습니다.장점: 가장 간단하고 명확하게 특정 액터 인스턴스와 연결할 수 있습니다.
단점: 매번 수동으로 연결해야 하므로, 오브젝트가 많거나 동적으로 생성되는 경우에는 비효율적입니다.
-
동적 할당 (블루프린트 로직)
BeginPlay시점에 찾기: 게임 시작 시점에 특정 타입의 액터를 찾아 변수에 할당합니다.Event BeginPlay뒤에Get All Actors Of Class노드를 추가합니다.Actor Class핀에BP_Door를 선택합니다.- 이 노드는 월드에 있는 모든
BP_Door액터 배열을 반환합니다. 만약 문이 하나뿐이거나 첫 번째 문만 필요하다면, 배열의 첫 번째 요소(Get (a copy))를 가져와Set TargetDoor노드에 연결합니다. - 장점: 코드로 동적으로 연결되므로 수동 설정이 필요 없습니다.
- 단점: 특정 태그(Tag)나 이름(Name)을 사용하지 않으면 정확한 인스턴스를 찾기 어렵거나, 여러 개 중 의도치 않은 것이 선택될 수 있습니다.
Overlap이벤트 시 할당: 플레이어가 문과 겹쳤을 때 해당 문을TargetDoor변수에 할당하는 방식입니다.- 플레이어 캐릭터 블루프린트에
Sphere Collision컴포넌트를 추가합니다. Sphere Collision의OnComponentBeginOverlap이벤트를 생성합니다.- 이벤트의
Other Actor핀을Cast To BP_Door노드에 연결하여Other Actor가BP_Door타입인지 확인합니다. Cast To BP_Door노드의As BP Door출력 핀을Set TargetDoor노드의 입력 핀에 연결합니다. (성공적으로 캐스팅되었을 때만 실행되도록Cast노드의 성공 실행 핀을 연결)- 장점: 플레이어와 상호작용하는 대상을 동적으로 참조할 수 있습니다.
- 단점: 충돌이나 특정 조건이 발생했을 때만 연결이 이루어집니다.
TargetDoor변수에BP_Door인스턴스가 성공적으로 할당되었다면, 이제 이 변수를 통해BP_Door블루프린트 내부의 함수나 변수에 접근할 수 있습니다.- 예를 들어, 플레이어 캐릭터 블루프린트에서
E키를 눌렀을 때TargetDoor를 열고 싶다면Event E키 입력 노드를 추가합니다.TargetDoor변수(Get 노드)를 가져옵니다.TargetDoor변수 노드의 출력 핀에서 드래그하여OpenDoor함수(BP_Door에 정의된 함수)를 검색하고 호출합니다.Event E키의 실행 핀을OpenDoor함수의 실행 핀에 연결합니다.
직접 참조의 장점과 단점
-
장점
- 직관적이고 간단합니다. 특정 오브젝트에 직접적으로 접근하므로 로직 이해가 쉽습니다.
- 성능 효율적: 한 번 참조가 설정되면, 직접적인 메모리 주소를 통해 접근하므로 빠르게 호출됩니다.
-
단점
- 강한 결합(Tight Coupling): 호출하는 블루프린트(예: 플레이어)가 호출되는 블루프린트(예: 문)의 특정 클래스 타입(BP_Door)을 직접적으로 알아야 합니다. 이는 나중에 문 대신 다른 종류의 상호작용 오브젝트(예: 레버)를 추가하려면 플레이어 블루프린트의 로직을 수정해야 할 수도 있다는 의미입니다.
- 유연성 부족: 동적으로 생성되거나 사라지는 오브젝트, 혹은 여러 종류의 오브젝트에 공통적으로 적용하기 어렵습니다.
- 안정성 문제: 만약
TargetDoor변수에 유효한 액터가 할당되지 않은 상태에서 함수를 호출하면,Access None오류가 발생하여 게임이 멈추거나 오작동할 수 있습니다. (이것이 가장 큰 단점이며, 이를 방지하기 위해IsValid노드를 통해 유효성 검사를 하는 것이 좋습니다.)
아래 다이어그램은 직접 참조를 사용할 때 Access None을 피하기 위해 변수 생성, 인스턴스 할당, 유효성 검사, 실패 분기를 어떤 순서로 배치해야 하는지 정리한 것입니다.
변수 타입을 맞추는 것만으로는 충분하지 않습니다. 월드 인스턴스를 할당하고, 호출 직전에 유효성을 검사해야 Access None을 피할 수 있습니다.
- 안전한 호출 순서
Set TargetDoor → IsValid → OpenDoor 호출하는 블루프린트에 대상 클래스의 Object Reference 변수를 만든다. Details 패널, BeginPlay 탐색, Overlap 이벤트 중 하나로 월드의 실제 액터를 넣는다. 키 입력이나 상호작용 직전에 참조가 아직 살아 있는지 확인한다. 유효하면 OpenDoor 같은 대상 함수와 변수에 직접 접근한다. 비어 있으면 UI 안내, 재탐색, 무시 처리로 분기하고 직접 호출을 막는다.
- 01 변수 생성
호출하는 블루프린트에 대상 클래스의 Object Reference 변수를 만든다.
- 02 인스턴스 할당
Details 패널, BeginPlay 탐색, Overlap 이벤트 중 하나로 월드의 실제 액터를 넣는다.
- 03 IsValid 검사
키 입력이나 상호작용 직전에 참조가 아직 살아 있는지 확인한다.
- OK 함수 호출
유효하면 OpenDoor 같은 대상 함수와 변수에 직접 접근한다.
- None 실패 처리
비어 있으면 UI 안내, 재탐색, 무시 처리로 분기하고 직접 호출을 막는다.
직접 참조는 변수를 만드는 것보다 그 변수에 어떤 방식으로 인스턴스를 넣을지가 더 중요합니다.
다음 다이어그램은 수동 할당, BeginPlay 탐색, Overlap 갱신, IsValid 검사를 언제 함께 쓰면 좋은지 비교합니다.
변수 타입을 BP_Door Object Reference로 맞춘 뒤, 월드의 어떤 인스턴스를 넣을지 정해야 직접 호출이 의미를 가집니다.
- Object Reference참조를 채우는 방식별 사용처
Object Reference Details Instance Editable을 켠 뒤 월드에 배치된 BP_PlayerCharacter의 디테일 패널에서 BP_Door를 지정합니다. BeginPlay Get All Actors Of Class 결과를 Set TargetDoor로 넘기되, 여러 문이 있으면 태그나 배열 처리가 필요합니다. Overlap Other Actor를 Cast To BP_Door로 확인한 뒤 성공한 As BP Door를 TargetDoor에 저장합니다. IsValid E 키 입력에서 OpenDoor를 호출하기 전 유효하지 않은 참조는 안내나 무시 분기로 빼야 Access None을 막습니다.
- Details문이 하나로 고정되어 있으면 수동 할당
Details Instance Editable을 켠 뒤 월드에 배치된 BP_PlayerCharacter의 디테일 패널에서 BP_Door를 지정합니다.
- BeginPlay시작 시점에 월드에서 찾아 넣는다
BeginPlay Get All Actors Of Class 결과를 Set TargetDoor로 넘기되, 여러 문이 있으면 태그나 배열 처리가 필요합니다.
- Overlap플레이어가 가까운 문을 기억한다
Overlap Other Actor를 Cast To BP_Door로 확인한 뒤 성공한 As BP Door를 TargetDoor에 저장합니다.
- IsValid호출 직전에 비어 있는지 확인한다
IsValid E 키 입력에서 OpenDoor를 호출하기 전 유효하지 않은 참조는 안내나 무시 분기로 빼야 Access None을 막습니다.
직접 참조는 간단한 통신에는 효과적이지만, 대규모 프로젝트나 복잡한 시스템에서는 Access None 오류와 같은 문제로 인해 유지보수가 어려워질 수 있습니다.
아래 다이어그램은 직접 참조를 유지해도 되는 상황과 다른 통신 방식으로 넘겨야 하는 상황을 점검하는 기준입니다.
변수에 특정 액터 인스턴스를 담으면 함수 호출은 쉬워지지만, 할당 시점과 결합도를 함께 관리해야 합니다.
- Object Reference 변수
Reference BP_Door 타입 변수처럼 호출 대상의 실제 인스턴스를 저장합니다. 1 통신할 대상 블루프린트 클래스를 Object Reference로 고릅니다. 2 디테일 패널, BeginPlay 검색, Spawn 반환값 중 하나로 실제 액터를 넣습니다. 3 대상이 없거나 파괴된 상태에서 호출하지 않도록 유효성을 먼저 봅니다. 4 참조 핀에서 대상 함수나 변수에 접근해 원하는 동작을 실행합니다.
- Object Reference 변수
Reference BP_Door 타입 변수처럼 호출 대상의 실제 인스턴스를 저장합니다.
- 변수 타입 지정
통신할 대상 블루프린트 클래스를 Object Reference로 고릅니다.
- 인스턴스 할당
디테일 패널, BeginPlay 검색, Spawn 반환값 중 하나로 실제 액터를 넣습니다.
- Is Valid 확인
대상이 없거나 파괴된 상태에서 호출하지 않도록 유효성을 먼저 봅니다.
- 함수 호출
참조 핀에서 대상 함수나 변수에 접근해 원하는 동작을 실행합니다.
직접 참조를 안전하게 사용할 수 있는 경계를 추가로 정리합니다.
대상 종류가 늘어나거나 수명이 불확실하면 인터페이스나 디스패처로 바꾸는 편이 유지보수에 낫다.
| 질문 | 판정 |
|---|---|
| 항상 같은 인스턴스 하나를 가리키나? | 직접 참조가 읽기 쉽다. 레벨 변수나 Spawn 반환값을 저장한다. |
| 대상 클래스가 자주 바뀌나? | 인터페이스 메시지로 구체 클래스 의존을 줄인다. |
| 여러 대상이 동시에 들어야 하나? | 이벤트 디스패처로 알림을 발행한다. |
| 대상이 사라질 수 있나? | IsValid와 재할당 경로를 반드시 둔다. |
| 신호 | 해석 |
|---|---|
| 좋은 사용처 | 플레이어가 현재 문 하나를 열거나 UI가 특정 캐릭터 값을 읽는다. |
| 나쁜 사용처 | 호출자가 모든 상호작용 액터 클래스를 Cast로 나열한다. |
직접 참조는 가장 단순한 통신 방식이지만 참조를 얻는 시점과 대상 수명을 명확히 하지 않으면 빈 참조 오류가 생깁니다.
참조 변수는 값 저장일 뿐이므로, 어떤 이벤트에서 값이 채워지고 어떤 조건에서 호출되는지 따로 봐야 한다.
- 참조 획득
Placed Actor Details에서 레벨 인스턴스를 직접 할당한다. Overlap Actor Other Actor를 Cast 후 변수에 저장한다. SpawnActor Return Value를 바로 참조 변수로 보관한다.
- 호출 안전성
IsValid None과 Destroy된 액터를 분리한다. Cast Fail 기대한 타입이 아니면 실패 경로를 둔다. Lifetime 대상이 사라질 때 참조를 비우거나 다시 찾는다.
| 검수 | 의미 |
|---|---|
| 핵심 | 참조는 연결선이 아니라 값이므로 비어 있을 수 있다. |
| 검수 | 어디서 Set되고 어디서 Get되는지 한 화면에 보여야 한다. |