Random Location!?

I was really hoping to learn how to find a random point for the AI. In BP is easy but in C++ was confusing!! How can I go a bout to et a random location around the AI within 500 units?

I take it that you mean moving the AI to a random location and not spawning.

This shows how to do a basic random movement for nav in c++ under “C++: AI Controller” https://www.vikram.codes/blog/ai/01-basic-navigation

Yes, I meant random location to move to. The link is very useful thanks a lot but I meant the GetRandomReachablePointInRadius
Like this one

I tried to use it but I get so many errors all the time I ended up giving up trying blindly.

In that case, I would see this as an example of how that works: GetRandomReachablePointInRadius example

There could be other examples out there but its the first I found. The UE4 doc there doesn’t seem to be of much help really in that way.

	if (GetWorld()) {
		// get the current nav system from the world
		UNavigationSystem* navSystem = UNavigationSystem::GetCurrent(GetWorld());
		// check that we have a nav system
		if (navSystem) {
			// get our actors current location to pe used as our start position
			FVector startPosi = BotCharacter->GetActorLocation();
			// create a nav location to be used as our end position 
			// default will be set to our current position in case of failure to find a suitable end position
			FNavLocation endPosi = FNavLocation(startPosi);
			// attempt to get a random new position
			if (navSystem->GetRandomReachablePointInRadius(startPosi, searchRadius, endPosi)) {
				// if we were successfull in finding a new location get the MoveToLocation BlackboardKeyID
				FBlackboard::FKey BlackboardKey_MoveToLocation = Blackboard->GetKeyID("MoveToLocation");
				// check that we got the key
				if ( Blackboard->IsValidKey( BlackboardKey_MoveToLocation)) {
					// set the MoveToLocation BlackboardKeyID to our new location
					Blackboard->SetValue<UBlackboardKeyType_Vector>(BlackboardKey_MoveToLocation, endPosi.Location);
					// return succeeded now that we have set up our new loacation
					return EBTNodeResult::Succeeded;
				}
				else {
					// return Aborted if we can't find the Key as it will never succeed without a proper Key
					if (bForceSuccess) {
						return EBTNodeResult::Succeeded;
					}
					return EBTNodeResult::Aborted;
				}
			}
			// return in progress if their are currently no valid locations
			if (bForceSuccess) {
				return EBTNodeResult::Succeeded;
			}
			return EBTNodeResult::InProgress;
		}
	}

The search radius doesn’t appear to be shown but it should be just a float.

If you have trouble getting it to work, suppose I could pop over to UE4 on the other OS.

Edit - Its in the header https://github.com/JDonDuncan/AI_Example/blob/588e84435087afd51bc381b2f89aa0aa9c27a795/Source/AI_Example/Public/AI/BTNodes/BTTasks/AIE_GoToRandom_BTTaskNode.h

float searchRadius = 3000.0f;

UE4.10 so its a bit old now but good starting point, and if it still works, all the better :slight_smile:

It didn’t work for some reason. I think the UNavigationSystem is different now! Maybe the include is missing?
You’re an angel. Thanks a lot for your help.
I am coming from a BP background. When doing AI in BP the first easy thing to learn is random patrol. But in C++ :frowning: random patrol is being a headache for 2 days and still not sorted!

btw, I’m trying to make a custom BTTask that finds a random location!

So this code works* with UE4.25:

if (GetWorld()) {
	UE_LOG(LogTemp, Log, TEXT("Got world. Now trying to find nav area for random loc..."));
	// get the current nav system from the world
	//UNavigationSystem* navSystem = UNavigationSystem::GetCurrent(GetWorld());
	// check that we have a nav system
	UNavigationSystemV1* NavigationArea = FNavigationSystem::GetCurrent<UNavigationSystemV1>(this);

	if (NavigationArea) {
		UE_LOG(LogTemp, Log, TEXT("Found nav area"));
		// get our actors current location to pe used as our start position
		FVector startPosi = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
		// create a nav location to be used as our end position 
		// default will be set to our current position in case of failure to find a suitable end position

		UE_LOG(LogTemp, Error, TEXT("Start loc X: %d"), startPosi.X);
		UE_LOG(LogTemp, Error, TEXT("Start loc Y: %d"), startPosi.Y);
		UE_LOG(LogTemp, Error, TEXT("End loc X: %d"), endPosi.Location.X);
		UE_LOG(LogTemp, Error, TEXT("End loc Y: %d"), endPosi.Location.Y);
		UE_LOG(LogTemp, Error, TEXT("Search rad: %f"), searchRadius);

		UE_LOG(LogTemp, Error, TEXT("Test navArea: %s"), *NavigationArea->GetPathName());

		// attempt to get a random new position
		if (NavigationArea->GetRandomReachablePointInRadius(startPosi, searchRadius, endPosi)) {
			// if we were successfull in finding a new location...
			UE_LOG(LogTemp, Log, TEXT("Found new random loc"));
		}
		else {
			UE_LOG(LogTemp, Error, TEXT("Random loc failed!"));
		}

	}
	else {
		UE_LOG(LogTemp, Error, TEXT("Couldn't get nav area!"));
	}

}
else {
	UE_LOG(LogTemp, Error, TEXT("Couldn't get world!"));
}

…

eg .h file...
public:
        float searchRadius = 30.0f;

*There’s some things to deal with though and it doesn’t fully work so you will need to figure that out if you want to continue down this way.

Note: I had to use player pos as I don’t have a test project currently that fits what you’re doing.

To get UNavigationSystemV1 working…

In your VS or whatever I guess maybe (I’m using VS) need to open the c++ source code file for the “project name.build.cs” file and add the following simply with the other things in it:

	PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "NavigationSystem" });

Then rebuild or whatever.

Also remember to add in the include or whatever else you need:

#include "NavigationSystem.h"

https://answers.unrealengine.com/questions/822173/cannot-compile-unavigationsystem-in-4201.html

…That gets that all working. However, GetRandomReachablePointInRadius() always returns false for me. Probably requires some other things from the example project.

I’m only getting you started here. So I won’t be doing everything for you but if you work through the example project this code comes from you should be able to figure it out. Could take weeks. That’s programming for you. I don’t have that time to spend on someone else’s project.

Hope that helps. Keep researching and figuring it out or consider it a lost cause for now and move on. Or wait and see if someone has working code with the latest versions or search and try to find something else on github or elsewhere.

…
Quick suggestion for continuing this. Try going deeper with what he has. Such as it looks like you might need to start here and then get to the code above. But you probably don’t want to duplicate it and instead re-work it to something else assuming you can understand enough to do so.

1 Like
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "NavigationSystem" });

This was the missing piece of my puzzle. Thank you very much for your time and help. Very much appreciated :slight_smile:

My version is fairly simple but it works atm. For anyone looking to do a simple random patrol this my humble solution.

the header looks like this

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_GetRandomLocation.generated.h"

UCLASS()
class SIMPLESHOOTER_API UBTTask_GetRandomLocation : public UBTTask_BlackboardBase
{
	GENERATED_BODY()

private:
	FVector AiCurrentLocation;
	FVector RandomTargetLocation;

public:
	UBTTask_GetRandomLocation();
	UPROPERTY(EditAnywhere)
	float SearchRadius = 500.f;

protected:
	virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;

};

and the cpp looks like this:

#include "BTTask_GetRandomLocation.h"
#include "NavigationSystem.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"

UBTTask_GetRandomLocation::UBTTask_GetRandomLocation()
{
	NodeName = "Find Random Location";
}

EBTNodeResult::Type UBTTask_GetRandomLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	Super::ExecuteTask(OwnerComp, NodeMemory);

	AiCurrentLocation = OwnerComp.GetAIOwner()->GetPawn()->GetActorLocation();
	UNavigationSystemV1* NavArea = FNavigationSystem::GetCurrent<UNavigationSystemV1>(this);
	if (NavArea)
	{
		RandomTargetLocation = NavArea->GetRandomReachablePointInRadius(this, AiCurrentLocation, SearchRadius);
		UE_LOG(LogTemp, Warning, TEXT("Random Point: %s"), *RandomTargetLocation.ToString());
		OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(), RandomTargetLocation);
	}

	return EBTNodeResult::Succeeded;
}

Just don’t forget to add “NavigationSystem” in your [your project].build.cs.

If you wonder how behavior tree looks here’s the patrol tree:

Special thanks to QueueButton :slight_smile:

2 Likes

Its good to see you got it working, quite fast too :smile:

Thanks… yeah, I’m experienced with BP but new to CPP. So, I only need help to find my way around CPP. Like for example when you told me about the .build.cs file suddenly all my code made sense to VS2019 lol

Thanks again :slight_smile:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms