2종류의 Task 생성
Monster -> AI -> 새 C++ 클래스 추가 -> BTTaskNode -> BTTMonAttack
Monster -> AI -> 새 C++ 클래스 추가 -> BTTaskNode -> BTTMonTrace
BTTMonTrace.h / BTTMonTrace.cpp 생성
#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "BTTMonTrace.generated.h"
UCLASS()
class UNREAL_3TH_API UBTTMonTrace : public UBTTaskNode
{
GENERATED_BODY()
private:
// 추적 대상
UPROPERTY(EditAnywhere, Category = "Blackboard", meta = (AllowPrivateAccess = true))
FBlackboardKeySelector m_TargetKey;
// 이동 목적지
UPROPERTY(EditAnywhere, Category = "Blackboard", meta = (AllowPrivateAccess = true))
FBlackboardKeySelector m_RecentTargetPos;
// 추적 중 추적을 중단하기 위한 재평가 거리
UPROPERTY(EditAnywhere, Category = "Blackboard", meta = (AllowPrivateAccess = true))
float m_RevaluateRange;
public:
// Task 진입 시 호출
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
// Task 가 InProgress 상태면 매 틱마다 호출
virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
public:
UBTTMonTrace();
};
#include "BTTMonTrace.h"
#include "AIController.h"
#include "../Monster_Base.h"
#include "NavigationSystem.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Blueprint/AIBlueprintHelperLibrary.h"
#include "../../header/global.h"
UBTTMonTrace::UBTTMonTrace()
{
bNotifyTick = true;
m_TargetKey.AddObjectFilter(this, GET_MEMBER_NAME_CHECKED(UBTTMonTrace, m_TargetKey), AActor::StaticClass());
m_RecentTargetPos.AddVectorFilter(this, GET_MEMBER_NAME_CHECKED(UBTTMonTrace, m_RecentTargetPos));
}
EBTNodeResult::Type UBTTMonTrace::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
Super::ExecuteTask(OwnerComp, NodeMemory);
// 추적대상을 블랙보드 키에서 설정을 안해놨으면 Task 실패
if (m_TargetKey.IsNone() || m_RecentTargetPos.IsNone())
{
return EBTNodeResult::Failed;
}
// 행동 시킬 AIController 를 가져온다.
AAIController* pController = OwnerComp.GetAIOwner();
// 추적 대상을 알아낸다(블랙보드 키)
ACharacter* pCharacter = Cast<ACharacter>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(m_TargetKey.SelectedKeyName));
// 추적 대상이 캐릭터가 아니라면 실패
if (!IsValid(pCharacter))
{
return EBTNodeResult::Failed;
}
else
{
OwnerComp.GetBlackboardComponent()->SetValueAsObject(FName("TraceTarget"), pCharacter);
}
// 네비메시가 깔려있는 곳에서 목적지를 향해 길찾기를 통한 이동
UAIBlueprintHelperLibrary::SimpleMoveToLocation(pController, pCharacter->GetActorLocation());
// 현재 추적대상의 위치(최근 이동 목적지) 를 블랙보드에 기록해둔다.
OwnerComp.GetBlackboardComponent()->SetValueAsVector(m_RecentTargetPos.SelectedKeyName, pCharacter->GetActorLocation());
// 추적상태에 들어오면 몬스터를 이동상태로 만들어줌
AMonster_Base* pMonster = Cast<AMonster_Base>(pController->GetPawn());
pMonster->ChangeState(EMON_STATE::MOVE);
return EBTNodeResult::InProgress;
}
void UBTTMonTrace::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
// 추적대상을 블랙보드 키에서 설정을 안해놨으면 Task 실패
if (m_TargetKey.IsNone() || m_RecentTargetPos.IsNone())
{
// InProgress 상태를 중단함
FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
}
// 추적중에 추적대상이 공격범위안으로 들어오면, 추적 상태를 성공으로 중단시켜서
// 트리가 다시 루트부터 시작될 수 있도록 한다.
ACharacter* pTarget = Cast<ACharacter>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(FName("TraceTarget")));
if (!IsValid(pTarget))
{
// InProgress 상태를 중단함
FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
return;
}
// 몬스터의 공격범위
float fAttRange = OwnerComp.GetBlackboardComponent()->GetValueAsFloat(L"AttackRange");
AAIController* pController = OwnerComp.GetAIOwner();
AMonster_Base* pMonster = Cast<AMonster_Base>(pController->GetPawn());
if (!IsValid(pMonster))
{
// InProgress 상태를 중단함
FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
return;
}
// 몬스터와 타겟 사이의 거리
float Distance = FVector::Distance(pTarget->GetActorLocation(), pMonster->GetActorLocation());
// 몬스터와 타겟사이의 거리가 공격범위 안이면
if (Distance < fAttRange)
{
// 성공으로 반환해서, 행동트리가 Patrol 로 가는것을 막음
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return;
}
FVector vRecentDest = OwnerComp.GetBlackboardComponent()->GetValueAsVector(m_RecentTargetPos.SelectedKeyName);
// 현재 타겟의 위치가, 몬스터의 이동 목적지와 재평가거리 이상 멀어지면
if (m_RevaluateRange < FVector::Distance(pTarget->GetActorLocation(), vRecentDest))
{
// 현재 타겟의 위치로 다시 길찾기를 시도한다.
UAIBlueprintHelperLibrary::SimpleMoveToLocation(pController, pTarget->GetActorLocation());
// 현재 추적대상의 위치(최근 이동 목적지) 를 블랙보드에 기록해둔다.
OwnerComp.GetBlackboardComponent()->SetValueAsVector(m_RecentTargetPos.SelectedKeyName, pTarget->GetActorLocation());
}
}
블루프린트 BT_Melee 수정
우측 상단 블랙보드 누르고 새 키를 눌러서 위의 2항목을 추가해준다.
'언리얼 5' 카테고리의 다른 글
230919 StartMap - StartGameMode / StarHUD_Base | NewMap - SceneCapture2DComponent (0) | 2023.09.19 |
---|---|
230918 위젯 (0) | 2023.09.18 |
230914 몬스터 AI - Move (0) | 2023.09.15 |
230913 enum 찾기 / 카메라 진동 / 몬스터 인공지능 (0) | 2023.09.13 |
230912 무기 구현 / 몬스터 AI (0) | 2023.09.12 |