Add wildlife navigation support
This commit is contained in:
@@ -3,14 +3,19 @@
|
||||
#include "AgrarianWildlifeBase.h"
|
||||
#include "AgrarianGameCharacter.h"
|
||||
#include "AgrarianInventoryComponent.h"
|
||||
#include "AIController.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Navigation/PathFollowingComponent.h"
|
||||
#include "NavigationSystem.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
AAgrarianWildlifeBase::AAgrarianWildlifeBase()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
bReplicates = true;
|
||||
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
|
||||
AIControllerClass = AAIController::StaticClass();
|
||||
|
||||
GetCharacterMovement()->MaxWalkSpeed = WanderSpeed;
|
||||
GetCharacterMovement()->bOrientRotationToMovement = true;
|
||||
@@ -25,6 +30,10 @@ void AAgrarianWildlifeBase::BeginPlay()
|
||||
|
||||
SpawnLocation = GetActorLocation();
|
||||
Health = FMath::Clamp(Health, 0.0f, MaxHealth);
|
||||
if (HasAuthority() && !GetController())
|
||||
{
|
||||
SpawnDefaultController();
|
||||
}
|
||||
ChooseWanderTarget();
|
||||
BroadcastHealthChanged();
|
||||
BroadcastStateChanged();
|
||||
@@ -159,34 +168,174 @@ void AAgrarianWildlifeBase::ServerThink(float DeltaSeconds)
|
||||
|
||||
void AAgrarianWildlifeBase::ChooseWanderTarget()
|
||||
{
|
||||
FVector ReachableTarget = FVector::ZeroVector;
|
||||
if (ChooseReachableWanderTarget(ReachableTarget))
|
||||
{
|
||||
CurrentMoveTarget = ReachableTarget;
|
||||
ClearNavigationMove();
|
||||
return;
|
||||
}
|
||||
|
||||
const FVector RandomOffset = FVector(
|
||||
FMath::FRandRange(-WanderRadius, WanderRadius),
|
||||
FMath::FRandRange(-WanderRadius, WanderRadius),
|
||||
0.0f);
|
||||
|
||||
CurrentMoveTarget = SpawnLocation + RandomOffset;
|
||||
ClearNavigationMove();
|
||||
}
|
||||
|
||||
void AAgrarianWildlifeBase::MoveTowardTarget()
|
||||
{
|
||||
FVector DesiredDirection = FVector::ZeroVector;
|
||||
FVector DesiredTarget = GetActorLocation();
|
||||
float DesiredSpeed = WanderSpeed;
|
||||
|
||||
if (WildlifeState == EAgrarianWildlifeState::Fleeing && FocusActor)
|
||||
{
|
||||
DesiredDirection = GetActorLocation() - FocusActor->GetActorLocation();
|
||||
GetCharacterMovement()->MaxWalkSpeed = FleeSpeed;
|
||||
FVector DesiredDirection = GetActorLocation() - FocusActor->GetActorLocation();
|
||||
DesiredDirection.Z = 0.0f;
|
||||
if (DesiredDirection.IsNearlyZero())
|
||||
{
|
||||
DesiredDirection = GetActorForwardVector();
|
||||
DesiredDirection.Z = 0.0f;
|
||||
}
|
||||
|
||||
DesiredTarget = GetActorLocation() + DesiredDirection.GetSafeNormal() * FleeRadius;
|
||||
DesiredSpeed = FleeSpeed;
|
||||
}
|
||||
else if (WildlifeState == EAgrarianWildlifeState::Chasing && FocusActor)
|
||||
{
|
||||
DesiredDirection = FocusActor->GetActorLocation() - GetActorLocation();
|
||||
GetCharacterMovement()->MaxWalkSpeed = FleeSpeed;
|
||||
DesiredTarget = FocusActor->GetActorLocation();
|
||||
DesiredSpeed = FleeSpeed;
|
||||
}
|
||||
else if (WildlifeState == EAgrarianWildlifeState::Wandering)
|
||||
{
|
||||
DesiredDirection = CurrentMoveTarget - GetActorLocation();
|
||||
GetCharacterMovement()->MaxWalkSpeed = WanderSpeed;
|
||||
DesiredTarget = CurrentMoveTarget;
|
||||
DesiredSpeed = WanderSpeed;
|
||||
}
|
||||
|
||||
if (RequestNavigationMove(DesiredTarget))
|
||||
{
|
||||
GetCharacterMovement()->MaxWalkSpeed = DesiredSpeed;
|
||||
return;
|
||||
}
|
||||
|
||||
DirectMoveTowardLocation(DesiredTarget, DesiredSpeed);
|
||||
}
|
||||
|
||||
bool AAgrarianWildlifeBase::ChooseReachableWanderTarget(FVector& OutTarget) const
|
||||
{
|
||||
if (!bUseNavigationMovement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const UWorld* World = GetWorld();
|
||||
const UNavigationSystemV1* NavigationSystem = World ? FNavigationSystem::GetCurrent<UNavigationSystemV1>(World) : nullptr;
|
||||
if (!NavigationSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FNavLocation ReachableLocation;
|
||||
if (!NavigationSystem->GetRandomReachablePointInRadius(SpawnLocation, WanderRadius, ReachableLocation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutTarget = ReachableLocation.Location;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AAgrarianWildlifeBase::ProjectPointToNavigation(const FVector& CandidateLocation, FVector& OutProjectedLocation) const
|
||||
{
|
||||
if (!bUseNavigationMovement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const UWorld* World = GetWorld();
|
||||
const UNavigationSystemV1* NavigationSystem = World ? FNavigationSystem::GetCurrent<UNavigationSystemV1>(World) : nullptr;
|
||||
if (!NavigationSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FNavLocation ProjectedLocation;
|
||||
if (!NavigationSystem->ProjectPointToNavigation(CandidateLocation, ProjectedLocation, NavigationProjectionExtent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutProjectedLocation = ProjectedLocation.Location;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AAgrarianWildlifeBase::RequestNavigationMove(const FVector& TargetLocation)
|
||||
{
|
||||
if (!bUseNavigationMovement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AAIController* AIController = Cast<AAIController>(GetController());
|
||||
if (!AIController)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FVector ProjectedTarget = TargetLocation;
|
||||
if (!ProjectPointToNavigation(TargetLocation, ProjectedTarget))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FVector::DistSquared(GetActorLocation(), ProjectedTarget) <= FMath::Square(NavigationAcceptanceRadius))
|
||||
{
|
||||
AIController->StopMovement();
|
||||
ClearNavigationMove();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bHasNavigationMoveTarget
|
||||
&& AIController->GetMoveStatus() != EPathFollowingStatus::Idle
|
||||
&& FVector::DistSquared(LastNavigationMoveTarget, ProjectedTarget) <= FMath::Square(NavigationRepathDistance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const EPathFollowingRequestResult::Type MoveResult = AIController->MoveToLocation(
|
||||
ProjectedTarget,
|
||||
NavigationAcceptanceRadius,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
nullptr,
|
||||
true);
|
||||
|
||||
if (MoveResult == EPathFollowingRequestResult::Failed)
|
||||
{
|
||||
ClearNavigationMove();
|
||||
return false;
|
||||
}
|
||||
|
||||
LastNavigationMoveTarget = ProjectedTarget;
|
||||
bHasNavigationMoveTarget = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AAgrarianWildlifeBase::ClearNavigationMove()
|
||||
{
|
||||
bHasNavigationMoveTarget = false;
|
||||
LastNavigationMoveTarget = FVector::ZeroVector;
|
||||
}
|
||||
|
||||
void AAgrarianWildlifeBase::DirectMoveTowardLocation(const FVector& TargetLocation, float MovementSpeed)
|
||||
{
|
||||
ClearNavigationMove();
|
||||
GetCharacterMovement()->MaxWalkSpeed = MovementSpeed;
|
||||
|
||||
FVector DesiredDirection = TargetLocation - GetActorLocation();
|
||||
DesiredDirection.Z = 0.0f;
|
||||
if (!DesiredDirection.IsNearlyZero())
|
||||
{
|
||||
@@ -198,6 +347,11 @@ void AAgrarianWildlifeBase::EnterDeadState()
|
||||
{
|
||||
Health = 0.0f;
|
||||
SetWildlifeState(EAgrarianWildlifeState::Dead);
|
||||
if (AAIController* AIController = Cast<AAIController>(GetController()))
|
||||
{
|
||||
AIController->StopMovement();
|
||||
}
|
||||
ClearNavigationMove();
|
||||
GetCharacterMovement()->StopMovementImmediately();
|
||||
GetCharacterMovement()->DisableMovement();
|
||||
SetLifeSpan(0.0f);
|
||||
|
||||
Reference in New Issue
Block a user