Enabling DetourCrowd on Player Character for Avoidance with CrowdManager

I wanted to post this here for others as I spent some time trying to figure out how to make AI using DetourCrowd avoid running into the player.

First, you need to be using C++. The way I handled this was to go to Tools > New C++ Class, and make an Actor Component. Then in the component, you want the .h file to inherit from ICrowdAgentInterface, like this. I named my component PlayerCrowdAgentInterface:

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Navigation/CrowdManager.h"
#include "Navigation/CrowdAgentInterface.h"
#include "PlayerCrowdAgentInterface.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class AAYOURPROJECTNAME_API UPlayerCrowdAgentInterface : public UActorComponent, public ICrowdAgentInterface
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UPlayerCrowdAgentInterface();

	FVector GetCrowdAgentLocation() const;

	FVector GetCrowdAgentVelocity() const;

	void GetCrowdAgentCollisions(float& CylinderRadius, float& CylinderHalfHeight) const;

	float GetCrowdAgentMaxSpeed() const;

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	virtual void InitializeComponent();

		
};

And in the .cpp file:

#include "PlayerCrowdAgentInterface.h"

// Sets default values for this component's properties
UPlayerCrowdAgentInterface::UPlayerCrowdAgentInterface()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...

}


// Called when the game starts
void UPlayerCrowdAgentInterface::BeginPlay()
{
	Super::BeginPlay();


	UCrowdManager* CrowdManager = UCrowdManager::GetCurrent(this);
	if (CrowdManager)
	{
		ICrowdAgentInterface* IAgent = Cast<ICrowdAgentInterface>(this);
		CrowdManager->RegisterAgent(IAgent);
	}
	
}


// Called every frame
void UPlayerCrowdAgentInterface::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}

void UPlayerCrowdAgentInterface::InitializeComponent()
{
	Super::InitializeComponent();
}

FVector UPlayerCrowdAgentInterface::GetCrowdAgentLocation() const
{
	return GetOwner() ? GetOwner()->GetActorLocation() : FVector::ZeroVector;
}
FVector UPlayerCrowdAgentInterface::GetCrowdAgentVelocity() const
{
	return GetOwner() ? GetOwner()->GetVelocity() : FVector::ZeroVector;
}
void UPlayerCrowdAgentInterface::GetCrowdAgentCollisions(float& CylinderRadius, float& CylinderHalfHeight) const
{
	if (GetOwner()) {
		GetOwner()->GetSimpleCollisionCylinder(CylinderRadius, CylinderHalfHeight);
	}
}
float UPlayerCrowdAgentInterface::GetCrowdAgentMaxSpeed() const
{
	return 300;
}

Build then in UE attach the component to your player character.

3 Likes

Thanks Lot.Does this work with pawn Class as well?