Download

How do I use the navigation system with a pawn?

I am trying to move a pawn with the navmesh system. I am using the following code


void AArenaPawn::PrimaryAction()
{
	FHitResult Hit;
	APlayerController* PC = Cast<APlayerController>(GetController());
	UNavigationSystem* Nav = UNavigationSystem::GetCurrent(GetWorld());
	if (PC){
		PC->GetHitResultUnderCursor(ECC_GameTraceChannel1, false, Hit);
		if (Hit.bBlockingHit)
		{
			if (Nav)
			     Nav->SimpleMoveToLocation(PC, Hit.Location);
		}
	}
}

The problem is that the pawn doesn’t move. The running animations are playing. The execution flow seems to be normal, RequestMove is called and the status is set to “Moving”.

What else do I have to do? Which system is actually moving the pawn?

As far as i know, the Nav System only works with a MovementComponent. Pawns don’t have one (that’s what the Character Parent Class is for).
So you will need to add one.

Someone correct me if i’m wrong.

Pawns have a movement component but I think you intended to say “CharacterMovementComponent”? I actually want to avoid the character class all together. I am currently looking though the CharacterMovementComponent and I think I have found where the “magic” is happening. I think the important parts are ProjectLocationFromNavmesh and PhysNavWalking.

Any tips are greatly appreciated.


What I know so far:

SimpleMoveToLocation will call RequestMove on the PathFollwingComponent and it sets the status to “moving”. The PathFollwingComponent calls FollowPathSegment every frame if the status is “moving”.

FollowPathSegment calculates the velocity like this:


	
const FVector CurrentLocation = MovementComp->GetActorFeetLocation();
const FVector CurrentTarget = GetCurrentTargetLocation();
FVector MoveVelocity = (CurrentTarget - CurrentLocation) / DeltaTime;

I have no idea why it divides the velocity by deltatime.

It then calls


MovementComp->RequestDirectMove(MoveVelocity, bNotFollowingLastSegment);

which sets the velocity in the MovementComp.

I am calling


MovementComponent->MoveUpdatedComponent(MovementComponent->Velocity * DeltaTime, this->GetActorRotation(),false,&Hit,ETeleportType::None);

which moves my pawn directly to the target location. That is because Velocity is just ‘(CurrentTarget - CurrentLocation)’. So I went though all those sub systems and achieved nothing.


It is actually very simple, I am now using the navigation system directly.


void AArenaPawn::PrimaryAction()
{
	FHitResult Hit;
	APlayerController* PC = Cast<APlayerController>(GetController());
	UNavigationSystem* Nav = UNavigationSystem::GetCurrent(GetWorld());
	TArray<FVector> Locations;
	if (PC){
		PC->GetHitResultUnderCursor(ECC_GameTraceChannel1, false, Hit);
		if (Hit.bBlockingHit)
		{
			if (Nav){
				FPathFindingQuery Query;
				FAIMoveRequest MoveReq;
				MoveReq.SetGoalLocation(Hit.Location);

				PreparePathfinding(MoveReq, Query);
				FPathFindingResult PathFindingResult = Nav->FindPathSync(Query);
				if (PathFindingResult.IsSuccessful() && PathFindingResult.Path->IsValid()){
					for (auto &PathPoint : PathFindingResult.Path->GetPathPoints()){
						Locations.Add(PathPoint.Location);
					}
				}
			}
		}
	}
}

The function “PreparePathfinding” is temporarly copied from AIController. The array “Locations” will contain the path locations in world space which you can use to move your Pawn.