저번 포스팅에서는 NavigaitonSystem을 사용해서 적의 랜덤 이동을 구현했는데, 이번에 Behavior 시스템을 공부하면서 얘를 이용하는 것으로 이동 방식을 바꿔주었다.
물론 NavigaitonSystem을 계속 써도 되지만 아직 코드로 접근하는 방법에 대해 익숙치 않아 에디터와 같이 사용하는게 더 이해가 잘 될 것 같기 때문이다.
먼저 BehaviorTree와 BlackBoard의 이론부터 공부했다.
빠르게 구현하면서 이해해도 좋지만 그러면 뭐부터 해야할 지 꼬일 것 같기도 하고 확실하게 이해를 하고 가야 다른 예제에서 한 것들을 나에게 맞게 응용할 수 있을 것 같았다.
BehaviorTree
BehaviorTree는 AI의 행동 로직을 계층적으로 구성할 수 있게 도와주는 시각적 스크립팅 도구이다.
AI가 상황에 따라 어떤 행동을 취할지 결정하는 노드인 Select, Sequence, Decorator 등을 배치하여 복잡한 행동패턴을 눈으로 쉽게 설계할 수 있다.
시퀀스(Sequence)
- 자식 노드를 순서대로 실행
- 모든 자식 노드가 성공해야 이 시퀀스 자체가 성공했다고 판정됨
셀렉터(Selector)
- 자식 노드를 순서대로 평가
- 하나라도 성공하면 전체가 성공했다고 판정
데코레이터(Decorator)
- 특정 조건을 검사
- 행동을 반복하거나, 반전 등의 추가 제어를 위해 다른 노드에 부착해서 실행하는 형태
서비스(Service)
- BehaviorTree에 특정 브랜치가 활성화되어 있는 동안 주기적으로 실행
- Blackboard 값을 업데이트하거나 지속적인 환경 체크를 수행
태스크(Task)
- 실제 행동을 실행하는 가장 기본적인 노드
- 이동, 공격, 애니메이션 재생 등의 원하는 행동에 대한 블루프린트 연결로 실행
- Success, Failure, Running 상태를 반환하여 상위 노드에 전달
BlackBoard
Blackboard는 BehaviorTree를 동작하는데 필요한 데이터를 저장하는 키-값 데이터 저장소 같은 역할이다.
예시로 위치나 상태, 감지 여부 등을 기록해두면 BehaviorTree의 각 노드가 이 데이터를 참조해서 조건을 판단하고 각 행동을 실행시키는데 활용한다.
이제 이론은 이해했으니 실제 프로젝트에 적용해볼 것이다.
베이스 세팅
Content 폴더 밑에 AI 폴더를 만들어서 BehaviorTree와 Blackboard를 생성해주었다.
(폴더 위치는 자신의 폴더 구조에 맞게 알잘딱깔센)
그리고 NewKey를 눌러서 내가 사용할 값들을 추가해주었다.
나는 이렇게 IsOverRange와 타겟의 위치인 PlayerLocation, 시야를 벗어났는지를 확인하는 IsTargetFindRange를 추가해줬다.
(IsOverRange와 DefaultLocation은 추후 적의 이동 반경을 벗어났을 때를 구현하기 위해 미리 만들어두었으니, 굳이 생성하지 않아도 된다)
그리고 BehaviorTree를 켜서 만들어둔 블랙보드를 연결시켜준다.
이제 BehaviorTree에서 블랙보드의 값을 알 수 있게 되었다!
추격을 구현할 시퀀스 노드를 하나 생성하였다. (파란색은 데코레이션 노드인데 지금은 일단 무시, 이따가 추가할 것이다)
전체 노드는 다음과 같다.(밑에서 과정을 설명 예정)
그리고 태스크를 추가할 때는 상단의 New Task를 선택하면 된다.
Patrol 구현
이렇게 먼저 시퀀스를 연결시켜주고 이름은 한 눈에 파악하기 쉽게 Patrol Sequence로 변경해줬다.
(아 참고로 가장 왼쪽에 있는 move to 노드는 무시해도 된다. 지금 추가하는 내용인데 정리를 깜빡했다..ㅎㅎ)
그리고 순찰을 수행할 태스크를 하나 생성해주었다.
태스크 노드는 이렇게 구상하였다.
Get Random Reachable Point in Radius 라는 노드가 있어서 사용해보았다.
설정한 반경에 맞는 랜덤 포인트를 반환해주는 노드다.
그 반환값을 ai move to에 연결해주었고, 값이 잘 반환이 되었다면 Success를 반환시켜줬다.
그리고 자연스러운 움직임을 위해 적 AI가 움직이고 2초 동안 대기하는 Wait 노드를 추가해주었다.
Chase 구현
Chase하는 태스크를 하나 생성해주고,
블루프린트를 다음과 같이 연결해줬다.
플레이어 컨트롤러를 가져와서 Target Actor를 플레이어로 연결해줬다.
Acceptance Radius는 원하는 값으로 입력해주고 finish excute에서는 항상 부울 체크 확인하는 것을 잊지않기.
컴파일 후 저장한다 <- 이건 그냥 노드 추가할 때마다 하게 습관이 되었다..
이렇게 Chase 태스크를 시퀀스에 연결시켜준다.
애니메이션 몽타주
이제 공격을 구현할건데 트리를 연결하기 전에 공격 애니메이션 몽타주를 만들어주었다.
근데 그 전에 그냥 State Machine으로 애니메이션을 연결하면되는데 왜 몽타주를 쓸까?
State Machine은 캐릭터의 상태에 따라 애니메이션을 지속적으로 블렌딩해준다.
몽타주는 특정 애니메이션을 동적으로 재생하고 블렌딩, 인터럽트, 부분 애니메이션 등을 지원한다고 한다.
내가 구현할 공격같은 애니메이션은 특정 조건에서만 재생하고 돌아갈거기 때문에 몽타주를 선택했다.
이렇게 몽타주를 생성하고 원하는 공격 모션을 추가해준다.
자세한 내용은 점부된 블로그를 참고하면 좋을 것 같다.
https://makerejoicegames.tistory.com/382
언리얼엔진5 애니메이션 몽타주
https://docs.unrealengine.com/5.0/en-US/animation-montage-in-unreal-engine/ Animation Montage Animation Montages are animation assets that enable you to combine animations in a single asset and control playback using Blueprints. docs.unrealengine.com ▣
makerejoicegames.tistory.com
Attack 구현
다음으로는 공격을 구현할 것이다.
적 캐릭터 블루프린트에 들어가서 이벤트 그래프로 들어간다.
Attack이라는 커스텀 블루프린트를 만들고 play montage를 연결시켜준다.
그리고 On Completed와 On Interrupted에 Call On Attack End를 연결해주고 디버그를 위해 Print String을 연결해주었다.
Attack 태스크에 들어가서 다음과 같이 연결해주었다.
적 캐릭터에 있는 Attack 함수를 불러와서 실행시켜주었다.
만들어둔 공격 태스크를 behaviorTree로 가져와서 연결해줬다. (추격의 우선순위를 더 높게 잡았기 때문에 추격의 오른쪽으로 배치해줬다)
애니메이션 연결
애니메이션은 파라곤 에셋에 들어있던 블렌드 스페이스를 이용해주었다.
해당 애니메이션을 살펴보니까 Speed에 따라 idle, walk, run이 출력되는 것을 확인할 수 있었다.
그래서 speed 값만 연결시켜주고, 몽타주 슬롯을 연결해주었다.
몽타주 클릭해서 내가 만든 슬롯을 설정해주면 끝!
최종 Animation Graph
최종적으로 애니메이션은 다음과 같다.
이벤트 그래프는 언리얼의 기본 캐릭터인 마네퀸의 노드들을 그대로 가져오고 위의 부분에서 Shuld Move를 set 해주는 노드만 추가해주었다.
결과
이렇게 캐릭터가 시야에 보이지 않으면 천천히 순찰하다가 캐릭터가 시야에 들어오면 추격 후 공격하는 것을 볼 수 있다
트러블슈팅
이슈 1번 -> 공격 애니메이션 몽타주 실행안되는 현상
상황 : 블루프린트는 디버깅을 해봤을 때 모두 잘 연결되는 것을 확인했지만 공격 모션이 안뜸..
작업 순서
1. enemyCharacter에서 커스텀으로 Attack 이벤트 노드 생성(몽타주 연결해줌)
2. 생성한 Attack 이벤트 노드를 attack 태스크에 연결
3. 비헤이비어트리에 attack 태스크 연결(IsTargetFineRange)가 true이면 추격 후 공격
해결 : 적 애니메이션 그래프에 몽타주를 저장한 슬롯 연결로 해결..
이슈 2번 -> 'D:\UE5_project\2nd-Team9-CH3-Project\Intermediate\Build\BuildRulesProjects\HelloWorldModuleRules\..\..\..\..\Plugins\Developer\RiderLink\Source\RiderLink\RiderLink.Build.cs' 소스 파일을 찾을 수 없습니다. 라는 에러 상황
상황 : visual studio를 사용하고 있고, 다른 팀원의 깃 브랜치에 들어갔다가 아무것도 안하고 다시 내 브런치로 전환했더니 이런 에러가 떴다...
원인 : 브랜치 바꾸면서 날 수도 있고, 다른 엔진의 버전을 사용하고 있어서 그런 거일수도 있고, 원인은 다양하다고 한다.
나 같은 경우에는 라이더를 사용하고 있는 브랜치로 왔다갔다하면서 꼬인 것 같다.
해결 : 프로젝트 폴더 내에서 Intermediate 폴더, Binaries 폴더, 비주얼스튜디오 솔루션을 삭제한 뒤, 다시 솔루션을 생성하고 빌드해줬더니 해결되었다.
마지막 말
- 코드로 작업할 때 할 일들을 TODO로 주석처리해서 관리했는데, 이렇게 하니까 뭐부터 해야할 지 헷갈렸다.
그래서 오늘 이후부터는 우선순위를 정해서 TODO 1, TODO 2 이런식으로 넘버링해서 관리하는 것이 좋을 것 같다.
- 애니메이션 적용할 때, 기본적인 것들을 놓쳐서 시간을 많이 소모했다.. 몽타주를 만들어놓고서 연결을 안했다던지..
적의 속도로 애니메이션 상태를 바꾸는데, 애니메이션 이벤트 노드에서 이벤트 노드가 이상하게 들어가 있었다던지..
차근차근 설계한 내용대로 차분하게 보는 것이 좋을 것 같다.
'Unreal Engine' 카테고리의 다른 글
[ UE ] 적 공격할 때 카메라 깜빡이는 문제 (0) | 2025.02.28 |
---|---|
[ UE, C++ ] 오늘 배운 내용 정리 및 애니메이션에 대해 알게 된 꿀팁 (0) | 2025.02.26 |
[ UE, C++ ] 적 Navigation 랜덤 이동 구현하기 (0) | 2025.02.21 |
[ UE, C++ ] NavMeshVolume 추가 및 적 AI 추격 구현하기 (0) | 2025.02.20 |
[ UE, C++ ] 웨이브 시스템을 활용한 간단한 게임 만들기 (2) (0) | 2025.02.18 |