이전 글 보기
https://mountain-noroo.tistory.com/61
플레이어 추적하기
캐릭터가 추적 범위 내에 있으면
공격 범위 안에 있을 경우 공격
공격 범위 안에 없을 경우 추적하는 노드를 생성하였다.
EXecuteTask
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;
}
이 함수는 저번에도 말했듯 Task가 실행될 때 호출되는 함수로
여기에서는 추적대상의 위치를 기록하고
추적대상을 향해 이동한다
여기서 InProgress로 결과를 리턴하였기 때문에
다른 노드로 넘어가지 않고 이 Task에 머무르게 된다.
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);
return;
}
// 추적중에 추적대상이 공격범위안으로 들어오면, 추적 상태를 성공으로 중단시켜서
// 트리가 다시 루트부터 시작될 수 있도록 한다.
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());
}
}
오늘 새로 살펴 볼 것은 TickTask라는 함수로
이또한 BTTTaskNode 클래스로부터 오버라이드한 함수이고
매 틱마다 호출된다.
InProgress로 이 Task노드에서 계속 머물러있게 되었기 때문에
몬스터와 타겟 사이의 Distance가 공격 범위 안으로 들어왔을 때야 말로 FinishLatentTask()라는 결괏값을 반환하는 함수를 통해 이 노드에서 다음으로 넘어갈 수 있다.
참고로 보이드 함수이기 때문에 return으로 함수를 빠져나가지 않으면 다음 작업을 실행하여버리기 때문에 유의하여야 한다.
'언리얼 > Assortrack UE5' 카테고리의 다른 글
[언리얼] 학원 17일차: 버튼, RenderTexture (0) | 2023.09.19 |
---|---|
[언리얼] 학원 16일차: UMG: 언리얼 UI (0) | 2023.09.18 |
[언리얼] 학원 14일차: AI Controller 몬스터의 플레이어 탐색 (Decorater, Task) (0) | 2023.09.15 |
[언리얼] 학원 13일차: 데이터 테이블 핸들, AI Controller (0) | 2023.09.13 |
[언리얼] 학원 12일차: 데칼, 몬스터 개선(데이터 테이블) (0) | 2023.09.12 |