UE5 Smart Object System — AI 상호작용 프레임워크
Smart Object System은 UE5의 AI 생태계 플러그인 중 하나로, 월드의 “상호작용 가능한 지점”(앉기, 숨기, 음료 마시기 등)을 데이터로 정의하고 여러 AI 에이전트가 경쟁적으로 사용할 수 있게 관리합니다. MassAI, StateTree, EQS와 함께 사용하면 완성도 높은 AI 행동을 구성할 수 있습니다.
1. 플러그인 활성화
섹션 제목: “1. 플러그인 활성화”Edit > Plugins:- Smart Objects → 활성화- MassAI (선택적) → 활성화
Build.cs:PublicDependencyModuleNames.AddRange(new[]{ "SmartObjectsModule", "GameplayTags", "StateTreeModule",});2. SmartObjectDefinition 에셋
섹션 제목: “2. SmartObjectDefinition 에셋”// SmartObjectDefinition은 에디터에서 데이터 에셋으로 생성// Content Browser > 우클릭 > Miscellaneous > Data Asset// 클래스: SmartObjectDefinition
// 코드에서 슬롯 정의UCLASS()class UBenchSitDefinition : public USmartObjectDefinition{ GENERATED_BODY()
public: UBenchSitDefinition() { // 슬롯 2개 (벤치 좌석) FSmartObjectSlotDefinition Slot1, Slot2;
// 슬롯 위치 (오브젝트 로컬 공간) Slot1.Offset = FTransform( FRotator::ZeroRotator, FVector(-30.f, 0.f, 0.f)); Slot2.Offset = FTransform( FRotator::ZeroRotator, FVector(30.f, 0.f, 0.f));
// 태그: 이 슬롯이 제공하는 기능 Slot1.Tags.AddTag(TAG_SmartObject_Sit); Slot2.Tags.AddTag(TAG_SmartObject_Sit);
Slots.Add(Slot1); Slots.Add(Slot2); }};3. SmartObjectComponent 배치
섹션 제목: “3. SmartObjectComponent 배치”// 월드 오브젝트에 컴포넌트 추가UCLASS()class ABench : public AActor{ GENERATED_BODY()
UPROPERTY(VisibleAnywhere) USmartObjectComponent* SmartObjectComp;
UPROPERTY(EditAnywhere) USmartObjectDefinition* Definition;
public: ABench() { SmartObjectComp = CreateDefaultSubobject<USmartObjectComponent>( TEXT("SmartObject")); }
virtual void BeginPlay() override { Super::BeginPlay();
if (Definition) SmartObjectComp->SetDefinition(Definition);
// Smart Object 시스템에 등록 SmartObjectComp->RegisterWithSubsystem(); }};4. AI 에이전트에서 슬롯 클레임
섹션 제목: “4. AI 에이전트에서 슬롯 클레임”#include "SmartObjectSubsystem.h"#include "SmartObjectComponent.h"
UCLASS()class UMyAIComponent : public UActorComponent{ GENERATED_BODY()
FSmartObjectClaimHandle _claimHandle; USmartObjectSubsystem* _soSubsystem;
public: virtual void BeginPlay() override { Super::BeginPlay(); _soSubsystem = GetWorld()->GetSubsystem<USmartObjectSubsystem>(); }
// 특정 태그의 Smart Object 검색 및 클레임 bool TryClaimSeat() { if (!_soSubsystem) return false;
// 조건: "앉기" 태그를 가진 슬롯 검색 FSmartObjectRequestFilter Filter; Filter.BehaviorDefinitionClass = nullptr; Filter.RequiredTags.AddTag(TAG_SmartObject_Sit);
// 가장 가까운 오브젝트 찾기 FSmartObjectRequest Request( FBox::BuildAABB(GetOwner()->GetActorLocation(), FVector(500.f)), Filter);
FSmartObjectRequestResult Result; if (!_soSubsystem->FindSmartObject(Request, Result)) return false;
// 슬롯 클레임 _claimHandle = _soSubsystem->Claim(Result); if (!_claimHandle.IsValid()) return false;
// 클레임된 슬롯의 월드 트랜스폼 획득 FTransform SlotTransform; _soSubsystem->GetSlotTransform( _claimHandle, SlotTransform);
// AI를 슬롯으로 이동 MoveToTransform(SlotTransform); return true; }
// 슬롯 사용 시작 void StartUsing() { if (_claimHandle.IsValid()) _soSubsystem->Use(GetOwner(), _claimHandle); }
// 슬롯 해제 void Release() { if (_claimHandle.IsValid()) { _soSubsystem->Release(_claimHandle); _claimHandle = FSmartObjectClaimHandle::InvalidHandle; } }
virtual void EndPlay(EEndPlayReason::Type Reason) override { Release(); Super::EndPlay(Reason); }};5. StateTree와 연동
섹션 제목: “5. StateTree와 연동”StateTree에서 Smart Object 태스크 사용:- SmartObject Find Task → 조건에 맞는 슬롯 검색- SmartObject Claim Task → 슬롯 클레임- Move To Smart Object Task → 슬롯으로 이동- SmartObject Use Task → 사용 시작 / 애니메이션 재생- SmartObject Release Task → 슬롯 해제
StateTree 상태 구성 예:Idle → FindBench (EQS) → MoveToBench → SitDown → Sitting → StandUp → Idle ↑ SmartObject Find ↑ SmartObject Claim/Move ↑ Use ↑ Release6. 슬롯 쿼리 — EQS 연동
섹션 제목: “6. 슬롯 쿼리 — EQS 연동”// Environment Query System에서 Smart Object 슬롯을 쿼리 아이템으로 사용// EQS Generator: Smart Object Slot Generator// - Definition 필터// - Tag 필터// - 거리 기반 점수
// C++에서 직접 반경 쿼리TArray<FSmartObjectRequestResult> Results;FSmartObjectRequest Request( FBox::BuildAABB(AgentLocation, FVector(1000.f)), Filter);
_soSubsystem->FindAllSmartObjects(Request, Results);
// 점수 기반 정렬Results.Sort([&](const auto& A, const auto& B){ float DistA = FVector::Dist( GetSlotLocation(A), AgentLocation); float DistB = FVector::Dist( GetSlotLocation(B), AgentLocation); return DistA < DistB;});Smart Object System은 “어디서 무엇을 할 수 있는가”를 데이터로 정의해 AI 코드를 단순화합니다. 슬롯 클레임은 반드시 EndPlay 또는 AI 사망 시 해제해 다른 에이전트가 사용할 수 있도록 하세요. StateTree와 연동하면 Find → Claim → Move → Use → Release 워크플로를 노드 그래프로 선언적으로 구성할 수 있어 복잡한 AI 상호작용을 깔끔하게 관리할 수 있습니다.