Behavior Tree (AI 행동 시스템)

김여울·2025년 5월 8일

사전캠프

목록 보기
13/24

📚 AI가 어떻게 움직이고 행동을 결정하는지

🧠 AI의 상태 흐름 예시

  • 일반 상태 (Idle/Patrol)
    • 주변을 수색하거나 지정된 경로를 순찰
  • 추적 모드 (Chase)
    • 적이 일정 반경 내에 들어오면 상태 전환
    • 적을 따라감
  • 공격 모드 (Attack)
    • 적과의 거리가 가까워지면 공격 상태로 변경
    • 공격 애니메이션이나 데미지 처리 수행

➡ 각 상황에 맞게 행동이 전환되는 기준(조건) 을 설정하고, 그에 따라 적절한 행동을 수행

Behavior Tree

  • AI의 행동을 시각적으로 구성할 수 있는 트리 구조 시스템
  • Behavior Tree를 에셋으로 만들 수 있고 AI 컨트롤러에서 사용할 수 있다

🌀 Behavior Tree 구성 요소

1️⃣  Root (루트)
   - 트리의 시작점
   - 아래 노드들을 실행하게 만드는 진입 지점
2️⃣  Selector (셀렉터)
   - 선택 노드
   - 조건을 검사하여 상황에 맞는 / 맞지 않는 태스크를 구분해 실행
   - 왼쪽부터 순서대로 자식 노드를 실행
   - 성공하는 노드를 찾을 때까지 시도함
   - 하나라도 성공하면 나머지는 실행하지 않고 중단
3️⃣  Sequence (시퀀스)
   - 순차 실행 노드
   - 자식 노드를 왼쪽부터 순서대로 연달아 실행
   - 모든 자식이 성공해야 전체가 성공
   - 하나라도 실패하면 중단
4️⃣  Parallel (페럴럴)
   - 동시 실행 노드 (여러 태스크를 묶어 한 번에 실행)
   - 자식 노드를 같이 실행
   - 어떤 조건에서 멈출지는 설정에 따라 다름 
    (예) 하나만 성공해도 전체 성공 or 모두 성공해야 전체 성공
5️⃣ Task (테스크)
   - 실제 행동이 일어나는 곳
    (예) 이동하기, 공격하기, 대기하기 등
6️⃣ Decorator (데코레이터)
   - 조건을 추가하거나 특정 기능을 추가하는 노드
   - 실행 가능 / 실행 불가능
   - 해당 노드 또는 서브트리의 실행 여부를 결정
    (예) 플레이어가 보일 때만 실행, 체력이 50% 이상일 때만 실행
7️⃣  Service (서비스)
   - 백그라운드에서 지속적으로 실행되는 기능
     (예) 일정 주기마다 플레이어 위치 갱신, 타겟 확인 등
   - 특정 노드가 활성화된 동안 계속 돌아감

구성 요소설명
Root트리의 시작점
Selector자식 중 하나라도 성공하면 OK
Sequence자식 전부 성공해야 OK
Parallel자식들을 동시에 실행
Task실제 행동 수행
Decorator실행 조건 부여
Service주기적 정보 업데이트 등 지속 실행

  • Simple Parallel
    전체 분기와 또 하나의 노드를 동시에 실행

📍BT_AICharacter

  • Behavior Tree 생성
  • Move To (Task)
    • 블루프린트에 캐릭터를 특정 위치까지 움직이게 하는 태스크
    • 📍 Move To: invalid ➡ 블랙보드(데이터를 저장하고 내보내는 에셋)을 만들어야 함

🔻BlackBoard

📍BB_AICharacter

  • BlackBoard 생성
  • 블랙보드 키 생성
    • SelfActor (오브젝트) : 특정 액터나 컴포넌트를 기억하고 추적하는 용도
    • TargetPosition (벡터) : AI가 “어디로 이동할지” 또는 “어디를 바라볼지”를 결정할 때 사용하는 위치 데이터

🔻Decorator

📍BTD_IsNearPlayer

  • 데코레이터 추가
    • Move To 태스크 2개
      ➡ 조건에 따라 설정을 해주는게 달라야함
      ➡ 데코레이터 추가하기
    • 조건 확인 후 그 안에서 실행도 가능
    • 새 데코레이터에서 만들고 노드 추가하기

▶ BTD_IsNearPlayer 일 때는 2번 태스크 실행
▶ 아닌 경우에는 3번 태스크 실행됨 ➡ TargetPosition을 어떻게 설정하냐에 따라 다름

✔ TargetPosition 다르게 설정 ➡ 데코레이터(BTD_IsNearPlayer) 에서 설정하기

  • 함수 오버라이드에서 PerformConditionCheck
    • 이 값이 True면 실행 / False면 실행안함 주장
    • 뒤에 AI가 붙은 항목들은 AI 컨트롤러가 조정할때 우선 실행되는 버전

  • 플레이어가 가까이 있는지 검사하기
  • Sphere Overlap Actors
    • 구 형체를 오버랩(겹침)을 판정해서 어떤 actor들이 들어있는지 확인하는 장치
    • 구 형태의 중심좌표는 이 블루프린트들이 가지고 있는 Owner Actor의 위치
    • 자신의 위치에서 구 형체를 검출
  • Sphere Radius (반경)
    • 1000 이내(10m)의 반경에 들어오면
  • Object Types
    • 배열로 받음 (Make Array)


어떤 항목을 받을지?

  • 주인공만 필요한 상황이므로, 폰(Pawn) 타입만 검색
  • 검출된 액터들이 배열(Out Actors)로 반환
  • 그중에서 주인공만 찾으면 되므로 Find 노드를 사용
    ✔ 이때 대상이 캐릭터든 폰이든 상관없음

  • Find 노드를 사용하여 Out Actors 배열 내에서 플레이어 폰이 존재하는지 확인
  • 해당 액터가 배열에 존재할 경우 ➡ 해당 인덱스(0 이상)를 반환 ➡ 후속 작업 수행
  • 존재하지 않을 경우 ➡ -1을 반환 ➡ 로직 중단 또는 예외 처리

✔ 반환된 인덱스가 -1인지 먼저 확인해야 하며 이를 위해 Branch 노드를 사용

  • 1인지 비교 (== -1)
    • True면 = 주변에 플레이어 없음 → 실패 처리
    • False면 = 플레이어 있음 → 성공 처리
  • Branch 노드로 분기:
    • 조건이 True → Return Value : false (실행 실패)
    • 조건이 False → Return Value : true (실행 성공)

Find 결과의미행동 실행 여부
-1액터 없음❌ 실행 안 함 (false)
0 이상액터 있음 (인덱스)✅ 실행함 (true)

  • TargetPosition을 블랙보드에 저장하기
  • Get Blackboard (데이터를 저장하고 내보냄)
  • Set Value as Vector
    • 블랙보드 안에 있는 값을 벡터로 저장
    • Key Name
      • StringToName : 블랙보드에 있는 스트링 값Name으로 변환해서 벡터를 저장 가능
    • Vector Value : 플레이어 폰의 위치 넣기

💥 오류


▶ BTD(Behavior Tree Decorator)는 자체적으로 블랙보드에 대한 직접적인 정보가 없음
➡ 어떤 액터가 해당 블랙보드를 사용하는지 먼저 알아야 함
Get Blackboard 노드의 Target을 자기 자신(Self) 이 아니라, BTD의 Owner Actor로 연결

🔻Service

📍BTS_FindingRandom

  • 3번 태스크의 Target Position 설정하기
  • Service
    • 새 서비스 만들기
      ▶ 서비스가 처음 활성화될 때 호출

활성화 됐을 때 Target Position을 랜덤하게 생성해야함 ➡ 내비게이션 활용

Nav Mesh Bounds Volume

내비게이션 시스템

  • 넓은 땅에서 어느 위치로 가야 최적의 경로인지 찾아주고 장애물이 있으면 피해가기도 함
용어의미설명
내비게이션 (Navigation)AI가 경로를 찾는 전체 시스템경로 탐색, 장애물 회피 등 전체 로직
내비메시 (NavMesh)내비게이션에 사용되는 길 정보 데이터AI가 걸을 수 있는 영역을 격자처럼 표시한 맵
내비메시 바운드 볼륨 (Nav Mesh Bounds Volume)내비메시가 생성될 영역을 지정하는 3D 박스이걸 배치하지 않으면 AI가 경로를 모름

  • 배치한 후 P 키를 누르면 녹색으로 내비메시가 표시 ➡ AI 내비게이션 시스템이 움직일 수 있는 영역
  • 거리 지정
    • 스케일을 키우기
    • 세부 설정(디테일) > 브러시 설정

  • AI가 이동할 랜덤 좌표(Finding Random Position)를 찾기 위한 블루프린트 작업으로 넘어감
    Get Random Location in Navigable Radius 노드를 이용해 이 녹색 영역 내에서 랜덤 좌표를 가져오기

  • Get Random Location in Navigable Radius
    • 특정 위치(Origin)를 중심으로 설정한 반경 안에서 AI가 이동 가능한 랜덤 위치를 찾아줌
    • 이 랜덤 위치는 반드시 내비메시(NavMesh) 안에 있어야 정상적으로 작동
      ➡ 내비 영역 밖이면 결과가 유효하지 않음
      • Origin 기준 Owner Actor의 현재 위치(AI 자신을 기준으로 탐색)
      • Radius (반경) 2000(20m)으로 확장하면 탐색 범위를 넓힐 수 있음
      • Return Value (Boolean)
        ➡ 결과 위치가 실제로 AI가 갈 수 있는 위치이면 true
        ➡ 갈 수 없는 위치(예: 내비메시가 없거나 장애물만 있는 곳)이면 false
Return Value의미처리 방식
falseAI가 이동할 수 없는 위치 (장애물, 내비메시 없음)❌ 블랙보드에 저장하지 않음
❌ Move To 등 행동 실행 X
trueAI가 실제로 이동 가능한 유효한 위치✅ 블랙보드에 위치값 저장 (Set Blackboard Value)
✅ Move To 등 행동 실행 O

이 좌표를 블랙보드에 set 해두면 이후 행동 노드에서 해당 위치로 이동하거나 추적하는 데 사용할 수 있음

  • Get Blackboard 블랙보드 컴포넌트를 가져옴 (Get)

  • Set Value as Vector 해당 블랙보드에 값(Vector)을 저장 (Set)

  • 서비스 추가
    : 랜덤한 위치를 탐색하고 움직이기

  • 1번 노드 BTD_IsNearPlayer + Move To (TargetPosition)

    • 데코레이터는 조건 검사 역할
      (예) 플레이어가 일정 거리 안에 있는지 확인
      • 조건이 참일 경우에만 아래의 Move To 노드가 실행됨
      • 2번 테스크 실행 조건을 데코레이터로 제어하는 구조
  • 2번 노드 Move To (TargetPosition) + BTS_FindingRandom

    • 이 Move To 노드는 서비스와 함께 실행됨
      • 서비스는 특정 주기로 실행되어 블랙보드 값을 갱신하거나 환경을 체크함
        (예) 일정 시간마다 TargetPosition을 랜덤하게 갱신
구분설명
왼쪽 (2번)데코레이터(BTD_IsNearPlayer)가 조건 만족할 때만 Move To 실행
오른쪽 (3번)Move To 실행 시, 동시에 BTS_FindingRandom 서비스도 함께 작동

💡정리

  • 0번인 Selector 먼저 실행
    • 셀렉터에서 왼쪽이 참인지 체크
    • 자손 중 선택 가능한 것 하나만 실행
      • 참이면 왼쪽, 거짓이면 오른쪽을 실행
      • 1번 검사 성공하면 2번 실행시키고 끝
      • 1번 실행 실패하면 3번으로 넘어감
      • 왼쪽 ➡ 오른쪽 순으로 실행
  • 가까우면 움직여라
    • Target Position(2) : 데코레이터에서 정해줌
  • 아니면 움직여라
    • target position(3) : 서비스가 태스크 실행 중에 자동으로 주기 갱신함
      ✔ 오른쪽 테스크 노드가 실행이 되어야 검사가 이루어짐
  • 우선 순위 : 데코레이터 > 서비스 > 테스크
  • Sequence는 자손을 순서대로 왼쪽 ➡ 오른쪽 순으로 실행
  • Simple Parallel 여러 가지를 동시에 실행

📍서비스(BTS_FindingRandom)

: 처음 실행했을 때만 랜덤 포지션을 확인
➡ 랜덤 포지션은 target position에 도달하게 되면 새로 Target Position을 설정해야함

  • 함수 추가

  • Event Tick
    • 일정시간 마다 실행됨
    • 액터의 위치를 가져와 블랙보드의 위치와 비교
    • 거리의 길이가 만약 10cm보다 작으면 다시 설정
  • 조건 동일
  • Get Actor Location와 블랙보드의 액터를 Owner Actor에 연결

0개의 댓글