블루프린트 통신 소개
블루프린트 통신이 왜 필요한가?
- 게임 내 액터들이 상호작용하려면 서로 정보를 주고받거나 명령을 내려야 함
- 이를 위해 블루프린트간 통신이 필요
- 데이터 교환
- 한 블루프린트가 가진 데이터를 다른 블루프린트가 알 필요가 있음
- 이벤트 알림
- 특정 사건이 발생했음을 다른 블루프린트에게 알려야 함
레벨 블루프린트
레벨 블루프린트 활용법
- 레벨 종속성
- 각 레벨마다 단 하나만 존재하는 특별한 블루프린트
- 해당 레벨에 국한된 로직을 처리하는데 사용
- 주요 사용 사례
- 레벨 시작/종료 이벤트
- 게임 시작 시 인트로 시퀀스 재생, 특정 조건 달성 시 레벨 종료 로직 실행
- 레벨 전체 관리
- 해당 레벨의 점수 관리, 목표 관리 등 레벨 전역 변수 및 함수 정의
- 다른 블루프린트와의 통신
- 레벨 블루프린트 -> 액터
- 액터 -> 레벨 블루프린트(제한적)
- 장점
- 레벨 고유의 이벤트나 시퀀스를 구성하기 편리함
- 레벨에 배치된 모든 액터에 대한 참조를 에디터에서 쉽게 설정 가능
재사용 가능한 블루프린트 생성
재사용 가능한, 모듈화된 블루프린트 설계 및 생성
- 캡슐화
- 관련된 데이터와 기능을 하나의 독립적인 단위로 묶어 관리
- 모듈식 설계
- 게임을 구성하는 요소들을 작은 블루프린트로 나누어 개발
- 각 블루프린트는 독립적으로 테스트하고 수정할 수 있음
- 통신을 위한 준비
- 퍼블릭 변수
- 외부에서 값을 읽거나 설정할 수 있도록 공개된 변수
- 퍼블릭 함수
- 외부에서 호출하여 특정 행동을 지시할 수 있는 함수
- 이벤트 디스패치
- 특정 상황 발생 시 외부에 알릴 수 있는 신호
- 인터페이스 구현
- 표준화된 방식으로 상호작용할 수 있도록 인터페이스 함수 구현
퍼블릭 변수
퍼블릭 변수와 직접 참조
- 참조가 핵심
- 통신하려는 대상 블루프린트의 특정 인스턴스에 대한 주소 값(참조)를 알아야 함
- 퍼블릭 접근
- 대상 블루프린트 내에서 눈 모양 아이콘 활성화를 통해 설정된 변수는 외부에서 값을 읽거나 쓸 수 있음
형변환
형 변환 방법
- 타입 확인 및 변환
- 많은 경우(특히 이벤트 발생 시) 얻게 되는 액터 참조는 Actor 또는 PrimitiveComponent와 같은 일반적인 상위 클래스 타입
- 참조가 실제로 우리가 원하는 특정 자식 블루프린트 클래스(예: BP_EnemyCharacter)의 인스턴스인지 확인하고, 맞다면 해당 타입으로 '취급'할 수 있도록 변환하는 과정
- Cast To [블루프린트 클래스명] 노드
- 이 노드에 검사하고 싶은 오브젝트 참조를 연결
블루프린트 인터페이스
블루프린트 인터페이스 개념
- "무엇을 할 수 있는지" 만 정의
- 인터페이스는 특정 함수들의 '명세(Specification)'만을 정의
- 수의 이름, 입력 파라미터, 반환 값 등이 여기에 해당
- 구현은 각자 알아서
- 이 인터페이스를 '구현(Implement)'하는 각각의 블루프린트들은 인터페이스에 정의된 함수들을 자신만의 방식으로 실제로 만듬
- 생성 방법
- 블루프린트 인터페이스 에셋 생성
- 콘텐츠 브라우저에서 우클릭 > Blueprints > Blueprint Interface
- 함수 정의
- 인터페이스 에디터에서 새로운 함수들을 추가하고, 필요한 입력/출력 파라미터를 설정
- 블루프린트에서 인터페이스 구현
- 인터페이스를 사용할 블루프린트를 열고, Class Settings > Interfaces 패널에서 Add 버튼을 눌러 만든 인터페이스를 추가
- 인터페이스 함수 실제 구현
- 인터페이스를 추가하면, My Blueprint 패널의 Interfaces 섹션에 해당 함수들이 나타남
- 함수들을 더블클릭하거나 우클릭하여 Implement Event (또는 Implement Function)를 선택하여 실제 로직을 작성
- 인터페이스 메시지 호출
- 다른 블루프린트에서 대상 액터의 참조를 통해 인터페이스 함수 노드(이름 뒤에 (Message)가 붙어있고, 편지봉투 아이콘이 있음)를 호출
이벤트 디스패치
이벤트 디스패치란?
- 한 블루프린트에서 발생한 이벤트를 여러 다른 블루프린트에게 동시에 알리는 기능
핵심 원리
- 이벤트 발송자(Event Broadcaster/Dispatcher)
- 특정 사건(이벤트)이 발생 했음을 알리는 주체
- 내부에 "이벤트 디스패처"라는 특별한 변수를 가짐
- 이벤트 수신자(Event Listener/Subscriber)
- 특정 이벤트에 관심을 가지고, 해당 이벤트가 발생하면 정해진 행동을 수행하는 주체
- 발송자의 이벤트 디스패처에 자신의 함수나 이벤트를 Bind함
- 이벤트 호출(Call/Dispatch)
- 발송자 쪽에서 이벤트 디스패처를 호출(Call)하면 해당 디스패처에 등록된 모든 수신자들의 함수/이벤트가 실행됨
사용 단계
1. 이벤트 디스패처 생성
- 발송자 블루프린트의 My Blueprint 패널 > Event Dispatchers 섹션에서 + 버튼을 눌러 새 디스패처를 만듬
- 필요하다면 디테일 패널에서 전달할 파라미터(Inputs)를 정의
2. 이벤트 디스패처 호출
- 발송자 블루프린트 내에서 특정 조건이 충족되면, 해당 이벤트 디스패처 변수를 끌어와 Call 노드를 실행
- 파라미터가 있다면 값을 연결
3. 이벤트 바인딩
- 수신자 블루프린트에서 발송자 블루프린트의 인스턴스 참조를 얻습니다. 이 참조를 통해 대상 이벤트 디스패처에 Bind Event to [디스패처명] 노드를 사용하여 자신의 커스텀 이벤트나 함수를 연결
4. 이벤트 언바인딩
- 더 이상 이벤트를 수신할 필요가 없을 때 Unbind Event from [디스패처명] 또는 Unbind All Events from [디스패처명] 노드를 사용하여 등록을 해제할 수 있음
- 메모리 누수 방지 및 불필요한 호출 방지
장점
- 일대다(One-to-Many)통신
- 하나의 이벤트 발생으로 여러 객체가 동시에 반응 가능
- 느슨한 결합
- 발송자는 누가 자신의 이벤트를 듣고 있는지 알 필요가 없음
- 수신자는 발송자의 내부 로직을 몰라도 됨
- 동적 연결
- 런타임에 이벤트를 바인딩하거나 언바인딩하여 유연하게 연결 관계를 관리할 수 있음
단점
- 참조 필요
- 수신자가 이벤트를 바인딩하려면 발송자 객체에 대한 참조가 필요
- 순서 보장 안됨
- 기본적으로 바인딩된 이벤트들의 실행 순서는 보장되지 않음
- 과도한 사용 주의
- 너무 많은 디스패처와 바인딩은 디버깅을 어렵게 만들 수 있음
액터 구하기
액터를 구하는 방법
- Get All Actors Of Class 노드
- 현재 레벨에 스폰되어 있는 특정 클래스(및 그 자식 클래스)의 모든 액터 인스턴스를 찾아 배열로 반환
- 매우 강력하지만 성능 비용이 높은 연산
- BeginPlay처럼 초기화 시점에 한 번 사용하거나, 정말 필요할 때 제한적으로 사용해야함
- 매 프레임(Tick) 호출은 절대적으로 피해야 함
- Get Actor Of Class 노드
- Get All Actors Of Class와 유사하지만, 특정 클래스의 인스턴스 중 하나만(보통 첫 번째로 찾은 것) 반환
고려 사항
- IsValid 노드 활용
- 참조를 사용하기 전에 항상 IsValid 노드(물음표 아이콘)로 해당 참조가 유효한지(Null이 아닌지) 확인하는 습관을 들여야 예기치 않은 크래시를 방지할 수 있음
- 참조 캐싱(Caching)
- Get All Actors Of Class나 반복적인 트레이스 등으로 얻은 참조는 가능하면 변수에 저장해두고 필요할 때 재사용하여 성능 부하를 줄이는것이 좋음
마무리
블루프린트 통신은 언리얼엔진 프로젝트의 복잡성과 상호작용성을 한단계 끌어올리는 핵심 기술
각 통신 방법의 장단점을 명확히 이해하고 프로젝트의 특성과 미래의 확장 가능성까지 고려하여 가장 적합한 방법을 선택하는 것이 중요