블랙 보드 변수 추가
NCP가 플레이어를 발견 시 정보를 블랙 보드에 저장
Object 타입 Target 변수 생성, 기반 클래스 ABcharacter 지정
NPC 행동 패턴
플레이어를 발견 했는지 안했는지 에 따라 추격 및 순찰로 구분
셀렉터 컴포짓을 사용 해 트리 확장
추격에 우선 적으로 동작 할 수 있게 확장
Move To 태스트에 BlackboardKey : Target 지정
서비스 노드 사용
독립적 으로 동작하지 않고 컴포짓 노드에 부착 되는 노드
해당 컴포짓 노드에 속한 태스트가 동작 할 때 같이 실행
플레이어를 감지 하기에 적합
서비스 노드 구현
BTservice 부모로 하는 BTservice_Detect 클래스 생성
서비스 노드 활성화 시 TickNode 함수를 Interval 주기에 따라 호출
TickNode 함수에는 NPC 위치 기준으로 6미터 내의 캐릭터 감지
여러 캐릭터가 존재 할 수 있어서 OverlapMultiByChannel 함수 사용
캐릭터 정보를 Tarray로 전달
UCLASS()
class ARENABATTLE_API UBTService_Detect : public UBTService
{
GENERATED_BODY()
public:
UBTService_Detect();
protected:
virtual void TickNode(
UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};
#include "ABAIController.h"
#include "ABCharacter.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "DrawDebugHelpers.h"
UBTService_Detect::UBTService_Detect()
{
NodeName = TEXT("Detect");
Interval = 1.0f;
}
void UBTService_Detect::TickNode(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
//현재 컨트롤 중인 액터 참조
APawn* ControllingPawn = OwnerComp.GetAIOwner()->GetPawn();
if (nullptr == ControllingPawn) return;
UWorld* World = ControllingPawn->GetWorld();
//엑터 위치 값
FVector Center = ControllingPawn->GetActorLocation();
//충돌 범위
float DetectRadius = 600.0f;
if (nullptr == World) return;
//충돌 시 리턴 되는 액터 정보
TArray<FOverlapResult> OverlapResults;
FCollisionQueryParams CollisionQueryParam(NAME_None, false, ControllingPawn);
bool bResult = World->OverlapMultiByChannel(
OverlapResults,
Center,//액터 위치
FQuat::Identity,
ECollisionChannel::ECC_GameTraceChannel2, //Attack 트레이스 채널(공격과 같은 채널)
FCollisionShape::MakeSphere(DetectRadius),//구 충돌체 사용
CollisionQueryParam
);
//충돌 객체를 찾기 못하면 nullptr 입력
OwnerComp.GetBlackboardComponent()->SetValueAsObject(AABAIController::TargetKey, nullptr);
//디버그용 렌더링
DrawDebugSphere(World, Center, DetectRadius, 16, FColor::Red, false, 0.2f);
}
서비스 노드를 배치
BTservice_Detect 를 Selector 서비스 노드로 배치
NPC 탐지 영역에서 플레이어 컨트롤러 찾기
플레이어 컨트롤러를 파악 할 수 있는 IsPlayerController 함수 사용
캐릭터 감지 시 블랙 보드의 Target 값에 플레이어 캐릭터 등록 실패 시 Nullptr
ABAIController 에 Targetkey 추가
UCLASS()
class ARENABATTLE_API AABAIController : public AAIController
{
GENERATED_BODY()
static const FName TargetKey;
}
//Cpp
const FName AABAIController::TargetKey(TEXT("Target"));
BTservice_Detect 수정
충돌 된 액터에 플레이어 컨트롤러 확인
디버그로 캐릭터 감지 시 녹색 구체, 캐릭터와 연결된 선을 렌더링
ABCharacter controlMode 추가
NCP 상태 추가, 방향에 따라 회전 할수 있게 캐릭터 무브먼터 설정
최대 이동 속도가 플레이어 보다 낮게 설정
부자연스럽게 움직이는 부분 보강
UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
GENERATED_BODY()
protected:
enum class EControlMode
{
GTA,
DIABLO,
NPC
};
virtual void PossessedBy(AController* NewController) override;
}
void AABCharacter::SetControlMode(EControlMode NewControlMode)
{
//...
case EControlMode::NPC:
//이동 방향에 따라 회전 설정
bUseControllerRotationYaw = false;
GetCharacterMovement()->bUseControllerDesiredRotation = false;
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->RotationRate = FRotator(0.0f, 480.0f, 0.0f);
break;
}
}
void AABCharacter::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
//플레이어 컨트롤러 이면
if (IsPlayerControlled())
{
//디아블로 상태로 이동 속도 600
SetControlMode(EControlMode::DIABLO);
GetCharacterMovement()->MaxWalkSpeed = 600.0f;
}
else
{
//AIcontroller 이면 속도 300
SetControlMode(EControlMode::NPC);
GetCharacterMovement()->MaxWalkSpeed = 300.0f;
}
}
비헤어비어 트리 데코레이터 노드 사용
서비스 노드로 Target 키 값을 존재 여부 확인
블랙 보드의 값을 기반으로 특정 컴포짓의 실행 여부를 결정하는 데코레이터 노드 사용
추격 동작에 데코레이터 추가
키 값의 변경 감지 되면 현재 컴포짓 노드 실행 취소 할수 있게 변경
관찰자 중단 항목을 지정하지 않으면 태스가 모두 마무리 될때 까지 대기( 플레이어가 시야 밖인데 추적)
관찰자 중단에 Self로 지정
블랙 노드의 Target 키 설정
순찰 동작에 데코레이터 추가
반대 조건인 Is Not set 으로 지정, 동일하게 관찰자 중단 옵션 설정
'언리얼 C++ 게임 개발의 정석 > 11. AI 컨트롤러와 비헤어비어 트리' 카테고리의 다른 글
11.4 NCP 공격 모드 (0) | 2024.05.04 |
---|---|
11.2 비헤이비어 트리 시스템 (0) | 2024.04.30 |
11.1 AI Controller 와 내비게이션 시스템 (0) | 2024.04.29 |