언리얼 엔진
Unreal AI - 블루프린트를 C++로 바꾸기 전에 알게 된 것들 정리
로안님
2025. 4. 2. 18:27
Unreal Engine AI 정리
✅ 블루프린트와 C++의 양방향 통신
Unreal Engine에서는 블루프린트와 C++ 간의 양방향 통신이 기술적으로는 가능하지만, 실무에서는 구조적 복잡성과 유지보수성 문제로 인해 주의가 필요합니다.
- 블루프린트에서 C++ 호출:
- UFUNCTION(BlueprintCallable)로 C++ 함수를 블루프린트에서 호출 가능
- C++에서 블루프린트 호출:
- BlueprintImplementableEvent, BlueprintNativeEvent 등을 사용해 C++에서 블루프린트 이벤트 호출 가능
- 문제점:
- 지나치게 양방향으로 얽히면 구조가 복잡해지고, 의존성 증가로 인해 디버깅/유지보수 어려움
- 성능 저하 가능성 (특히 Tick에서 블루프린트 호출 반복 시)
- 권장 방식:
- 코어 로직은 C++에서 처리하고, 블루프린트는 시각적 조립이나 간단한 이벤트/이펙트 처리에 사용
✅ AI Behavior 구조 설계
AI는 Unreal의 Behavior Tree(BT) 시스템과 C++ 로직을 결합하여 하이브리드 방식으로 구성하는 것이 가장 이상적입니다.
- Behavior Tree (BT)
- 전체 AI의 흐름(조건 분기, 순서 제어 등)을 시각적으로 구성
- 블랙보드(Blackboard)를 통해 데이터 공유 및 조건 분기 가능
- C++의 역할
- 거리/범위/시야각 등의 계산 로직
- 복잡한 상태 조건, 캐릭터 내부 데이터 해석
- 블랙보드 값 갱신 (BTService에서 호출)
- 하이브리드 구조 권장
- 계산: C++ 함수로 작성 → BTService/BTTask에서 호출
- 분기: BTDecorator에서 블랙보드 기반 조건 판단
- 실행: BTTask에서 실제 행동 수행
✅ 데코레이터, 서비스, 테스크 판단 기준
AI 로직을 Behavior Tree에 넣을 때, 로직 성격에 따라 데코레이터/서비스/테스크를 구분해서 사용해야 성능과 유지보수성이 좋아집니다.
요소 사용 시기 특징 및 용도
Decorator | Task 실행 여부 판단 | - 간단한 조건 분기 (ex. 블랙보드 bool) |
- 한 번만 실행됨 (Tick 안 됨) | ||
- 복잡한 계산은 ❌ | ||
Service | 정보 지속 갱신 | - Tick마다 실행되어 블랙보드 값 갱신 |
- 거리 계산, 시야 체크 등 실시간 판단 | ||
Task | 행동 실행 | - 실제 공격/이동 등 AI 액션 처리 |
- 상태 변경 등 명령 수행 |
❗복잡한 계산은 데코레이터보다 Service에서 처리하고,
결과를 블랙보드로 넘긴 뒤 데코레이터는 그 값을 판단하는 구조가 가장 깔끔합니다.
✅ 멀티플레이 대응
멀티플레이 프로젝트에서는 AI 역시 네트워크 동기화를 고려해야 합니다.
모든 변수와 함수는 네트워크 동작 범위에 따라 적절히 지정해야 안정적인 멀티플레이가 가능합니다.
- 변수 동기화:
- UPROPERTY(Replicated)로 지정하여 클라이언트 간 변수 일치
- GetLifetimeReplicatedProps()에서 반드시 등록
- 함수 동기화:
- 서버에서 실행해야 할 함수: UFUNCTION(Server, Reliable)
- 모든 클라이언트에게 전파할 함수: UFUNCTION(NetMulticast, Reliable)
- 클라이언트에서만 실행: UFUNCTION(Client) (특수한 경우)
- AI 동기화 팁:
- AIController는 기본적으로 서버 전용 → 행동 결정은 서버에서만 처리
- 캐릭터의 상태 변경은 서버에서 결정 후 Replicate
- 애니메이션/이펙트는 Multicast 또는 클라에서 조건 기반 트리거
⚠️ 블루프린트에서 Replication 설정을 해도, 실제 동작은 C++ 구현 여부에 따라 달라지므로
핵심 로직은 C++에서 처리하는 것이 멀티플레이 안정성에 유리합니다.
이 구조를 기준으로 블루프린트 AI를 안정적으로 C++로 컨버팅하면서도,
BT 시스템과 멀티플레이 대응까지 고려한 설계가 가능합니다.