Thank you for your answer! First, I’ll show you my service code and tasks. First of all, please understand that the content may be long…! Sorry!!
First of all, I re-created the action tree today. With BT_Attack. BT_Attack ran. But I want to know why the existing BT_NPC doesn’t work…!
This picture is a weird thing to stop at the root when you play it.
void UBTService_SeePlayer::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0); // 플레이어 폰 가져오기
AAIController* AIController = OwnerComp.GetAIOwner(); // AI 컨트롤러 가져오기
APawn* NPC = AIController->GetPawn(); // AI 폰 가져오기
// AI의 시야에 플레이어가 보이면
if (AIController->LineOfSightTo(Player))
{
UWorld* World = NPC->GetWorld(); // AI 가 속한 월드 가져오기
FName PlayerPositionName = TEXT("PlayerPos");
FVector PlayerPosition = Player->GetActorLocation(); // 플레이어 위치 가져오기
OwnerComp.GetBlackboardComponent()->SetValueAsVector(PlayerPositionName, Player->GetActorLocation()); // 플레이어 위치 저장(Set은 변수에 못 담는다.)
FName TargetName = TEXT("Target");
OwnerComp.GetBlackboardComponent()->SetValueAsObject(TargetName, Player); // 타겟을 Player로 설정
// 플레이어와의 위치를 선과 점으로 표현
DrawDebugPoint(World, Player->GetActorLocation(), 10.0f, FColor::Green, false, 0.2f);
DrawDebugLine(World, NPC->GetActorLocation(), Player->GetActorLocation(), FColor::Green, false, 0.27f);
}
else
{
FName TargetName = TEXT("Target");
OwnerComp.GetBlackboardComponent()->SetValueAsObject(TargetName, nullptr); // 타겟을 null로 설정
}
}
bool UBTDecorator_AttackRange::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
Super::CalculateRawConditionValue(OwnerComp, NodeMemory);
APawn* NPC = OwnerComp.GetAIOwner()->GetPawn();
if (NPC == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("No NPC"));
return false;
}
FName PlayerName = TEXT("Target");
APawn* Player = Cast<APawn>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(PlayerName)); // 타겟인 플레이어 가져오기(캐스팅하기)
if (Player == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("No Target"));
return false;
}
IOLNPCInterface* NPCInterface = Cast<IOLNPCInterface>(NPC); // NPC가 인터페이스를 생성한 경우 캐스팅이 됨
// nullptr로 인터페이스가 없는지 확인을 해야 하는데 착각하고 nullptr을 넣지 않아서 인터페이스가 존재하는 상태에서 false가 되버림(그래서 npc가 자꾸 나를 쫓아오게 됨)
if (NPCInterface == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("No NPCInterface"));
return false;
}
float Distance = FVector::Dist(NPC->GetActorLocation(), Player->GetActorLocation()); // NPC와 플레이어 사이의 거리 구하기
float AttackRange = NPCInterface->AttackRange();
bool AttackRangeResult = Distance <= AttackRange;
return AttackRangeResult;
}
If I can explain this code, Service will keep you checking if the player can see it. If you see it, let’s make the target value the player. And then if it comes within the range of the attack, it attacks and if it doesn’t, it’s the same code that keeps you going.
I don’t know how to use English, so the sentence can be awkward because I use a translator. I’m sorry.