Basic walker AI
This commit is contained in:
parent
0beacfdd83
commit
6b5fcdf546
|
@ -4,6 +4,120 @@
|
|||
#include "WalkerAIController.h"
|
||||
|
||||
#include "Navigation/CrowdFollowingComponent.h"
|
||||
#include "Perception/AIPerceptionComponent.h"
|
||||
#include "Perception/AISenseConfig_Sight.h"
|
||||
#include "Perception/AISense_Sight.h"
|
||||
#include "WheeledVehicle.h"
|
||||
#include "WheeledVehicleMovementComponent.h"
|
||||
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
# define LOG_AI_WALKER(Verbosity, Text) UE_LOG(LogCarla, Verbosity, Text, *GetPawn()->GetName());
|
||||
#else
|
||||
# define LOG_AI_WALKER(Verbosity, Text)
|
||||
#endif // CARLA_AI_WALKERS_EXTRA_LOG
|
||||
|
||||
AWalkerAIController::AWalkerAIController(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer.SetDefaultSubobjectClass<UCrowdFollowingComponent>(TEXT("PathFollowingComponent"))) {}
|
||||
: Super(ObjectInitializer.SetDefaultSubobjectClass<UCrowdFollowingComponent>(TEXT("PathFollowingComponent")))
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
PrimaryActorTick.TickInterval = 5.0f; // seconds.
|
||||
|
||||
auto Perception = CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("AIPerception Component"));
|
||||
check(Perception != nullptr);
|
||||
SetPerceptionComponent(*Perception);
|
||||
|
||||
SightConfiguration = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("SightConfiguration"));
|
||||
SightConfiguration->SightRadius = 800.0f;
|
||||
SightConfiguration->LoseSightRadius = (SightConfiguration->SightRadius + 100.0f);
|
||||
SightConfiguration->PeripheralVisionAngleDegrees = 90.0f;
|
||||
SightConfiguration->DetectionByAffiliation.bDetectEnemies = true;
|
||||
SightConfiguration->DetectionByAffiliation.bDetectNeutrals = true;
|
||||
SightConfiguration->DetectionByAffiliation.bDetectFriendlies = true;
|
||||
|
||||
Perception->ConfigureSense(*SightConfiguration);
|
||||
Perception->SetDominantSense(SightConfiguration->GetSenseImplementation());
|
||||
Perception->OnPerceptionUpdated.AddDynamic(this, &AWalkerAIController::SenseActors);
|
||||
}
|
||||
|
||||
void AWalkerAIController::Tick(float DeltaSeconds)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
|
||||
switch (GetMoveStatus()) {
|
||||
case EPathFollowingStatus::Idle:
|
||||
case EPathFollowingStatus::Waiting:
|
||||
LOG_AI_WALKER(Warning, TEXT("Walker %s is stuck!"));
|
||||
bIsStuck = true;
|
||||
break;
|
||||
case EPathFollowingStatus::Paused:
|
||||
LOG_AI_WALKER(Log, TEXT("Walker %s is paused"));
|
||||
bIsPaused = true;
|
||||
TryResumeMovement();
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
FPathFollowingRequestResult AWalkerAIController::MoveTo(
|
||||
const FAIMoveRequest& MoveRequest,
|
||||
FNavPathSharedPtr* OutPath)
|
||||
{
|
||||
bIsStuck = false;
|
||||
LOG_AI_WALKER(Log, TEXT("Walker %s requested to move"));
|
||||
return Super::MoveTo(MoveRequest, OutPath);
|
||||
}
|
||||
|
||||
static bool VehicleIsMoving(const AWheeledVehicle *Vehicle)
|
||||
{
|
||||
const auto *MovementComponent =
|
||||
(Vehicle != nullptr ? Vehicle->GetVehicleMovementComponent() : nullptr);
|
||||
return
|
||||
(MovementComponent != nullptr) &&
|
||||
(MovementComponent->GetForwardSpeed() > 0.0f);
|
||||
}
|
||||
|
||||
static bool ContainsAMovingVehicle(const TArray<AActor *> &Actors)
|
||||
{
|
||||
for (auto *Actor : Actors) {
|
||||
if (VehicleIsMoving(Cast<AWheeledVehicle>(Actor))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AWalkerAIController::SenseActors(const TArray<AActor *> Actors)
|
||||
{
|
||||
if (!bIsPaused && ContainsAMovingVehicle(Actors)) {
|
||||
TryPauseMovement();
|
||||
}
|
||||
}
|
||||
|
||||
void AWalkerAIController::TryResumeMovement()
|
||||
{
|
||||
auto MoveRequestID = GetCurrentMoveRequestID();
|
||||
if (MoveRequestID == FAIRequestID()) { // equals invalid request.
|
||||
LOG_AI_WALKER(Error, TEXT("Walker %s: Invalid move ID"));
|
||||
} else {
|
||||
if (!ResumeMove(MoveRequestID)) {
|
||||
LOG_AI_WALKER(Error, TEXT("Unable to resume walker %s move"));
|
||||
} else {
|
||||
LOG_AI_WALKER(Log, TEXT("Resume walker %s's move"));
|
||||
bIsPaused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AWalkerAIController::TryPauseMovement()
|
||||
{
|
||||
auto MoveRequestID = GetCurrentMoveRequestID();
|
||||
if (MoveRequestID == FAIRequestID()) { // equals invalid request.
|
||||
LOG_AI_WALKER(Error, TEXT("Walker %s: Invalid move ID"));
|
||||
} else {
|
||||
if (!PauseMove(MoveRequestID)) {
|
||||
LOG_AI_WALKER(Error, TEXT("Unable to pause walker %s move"));
|
||||
} else {
|
||||
LOG_AI_WALKER(Log, TEXT("Pause walker %s's move"));
|
||||
bIsPaused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "AIController.h"
|
||||
#include "WalkerAIController.generated.h"
|
||||
|
||||
class UAISenseConfig_Sight;
|
||||
|
||||
UCLASS()
|
||||
class CARLA_API AWalkerAIController : public AAIController
|
||||
{
|
||||
|
@ -12,5 +14,34 @@ class CARLA_API AWalkerAIController : public AAIController
|
|||
|
||||
public:
|
||||
|
||||
AWalkerAIController(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
AWalkerAIController(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
virtual FPathFollowingRequestResult MoveTo(
|
||||
const FAIMoveRequest& MoveRequest,
|
||||
FNavPathSharedPtr* OutPath = nullptr) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SenseActors(TArray<AActor *> Actors);
|
||||
|
||||
bool WalkerIsStuck() const
|
||||
{
|
||||
return bIsStuck;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void TryResumeMovement();
|
||||
|
||||
void TryPauseMovement();
|
||||
|
||||
UPROPERTY(Category = "Walker AI Controller", VisibleAnywhere)
|
||||
UAISenseConfig_Sight *SightConfiguration;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
bool bIsPaused = false;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
bool bIsStuck = false;
|
||||
};
|
||||
|
|
|
@ -111,7 +111,7 @@ void AWalkerSpawnerBase::Tick(float DeltaTime)
|
|||
auto Walker = WalkersBlackList[Index];
|
||||
auto Controller = GetController(Walker);
|
||||
if ((Controller == nullptr) ||
|
||||
(Controller->GetMoveStatus() != EPathFollowingStatus::Moving)) {
|
||||
(Controller->WalkerIsStuck())) {
|
||||
WalkersBlackList.RemoveAtSwap(Index);
|
||||
if (Walker != nullptr) {
|
||||
Walker->Destroy();
|
||||
|
@ -129,7 +129,7 @@ void AWalkerSpawnerBase::Tick(float DeltaTime)
|
|||
if (Walker != nullptr) {
|
||||
Walker->Destroy();
|
||||
}
|
||||
} else if (Controller->GetMoveStatus() != EPathFollowingStatus::Moving) {
|
||||
} else if (Controller->WalkerIsStuck()) {
|
||||
TrySetDestination(*Walker);
|
||||
WalkersBlackList.Add(Walker);
|
||||
Walkers.RemoveAtSwap(Index);
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
DECLARE_LOG_CATEGORY_EXTERN(LogCarla, Log, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCarlaServer, Log, All);
|
||||
|
||||
// Options to compile with extra debug options.
|
||||
// Options to compile with extra debug log.
|
||||
#if WITH_EDITOR
|
||||
// #define CARLA_AI_VEHICLES_EXTRA_LOG
|
||||
// #define CARLA_AI_WALKERS_EXTRA_LOG
|
||||
// #define CARLA_ROAD_GENERATOR_EXTRA_LOG /// @todo #1 Crashes in Linux.
|
||||
// #define CARLA_SERVER_EXTRA_LOG
|
||||
// #define CARLA_TAGGER_EXTRA_LOG
|
||||
|
|
Loading…
Reference in New Issue