Download

how to move Character with AIController MoveToActor()?

Hi,

I’m trying to implement an AIController subclasses, that possesses an Character, and I’m trying to move the Character by calling MoveToActor() in the AIController. But, the Character doesn’t move.

My Character is a C++ class called Wanderer, subclassed from ACharacter, and then I have a BluePrint based on the C++ class called WandererBP. I’ve set my AIController subclass to be the AIController for WandereBP. according to the log files, my AIController subclass gets possession of WanderedBP, and I call MoveToActor() with a TargetPoint, but nothing happens afterwards.

I wonder what I’m doing wrong.

see relevant sources here:

Wanderer.h:


 
 #pragma once  
     
 #include "CoreMinimal.h"  
 #include "Logging/LogMacros.h"  
 #include "GameFramework/Character.h"  
 #include "Wanderer.generated.h"  
     
 DECLARE_LOG_CATEGORY_EXTERN(WandererLogCategory, Log, All);  
     
     
 UCLASS()  
 class ERZSEBET_API AWanderer : public ACharacter  
 {  
 	GENERATED_BODY()  
     
 public:  
 	// Sets default values for this character's properties  
 	AWanderer();  
     
 protected:  
 	// Called when the game starts or when spawned  
 	virtual void BeginPlay() override;  
     
 public:	  
 	// Called every frame  
 	virtual void Tick(float DeltaTime) override;  
     
 	// Called to bind functionality to input  
 	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;  
     
     
     
 }; 

Wanderer.cpp:


 
 #include "Wanderer.h"  
     
 DEFINE_LOG_CATEGORY(WandererLogCategory)  
     
     
     
 // Sets default values  
 AWanderer::AWanderer()  
 {  
  	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.  
 	PrimaryActorTick.bCanEverTick = true;  
     
     UE_LOG(WandererLogCategory, Log, TEXT("Wanderer created!"));  
 }  
     
 // Called when the game starts or when spawned  
 void AWanderer::BeginPlay()  
 {  
 	Super::BeginPlay();  
     
     UE_LOG(WandererLogCategory, Log, TEXT("Wanderer begin play!"));  
 }  
     
 // Called every frame  
 void AWanderer::Tick(float DeltaTime)  
 {  
 	Super::Tick(DeltaTime);  
     
     //UE_LOG(WandererLogCategory, Log, TEXT("Wanderer tick!"));  
 }  
     
 // Called to bind functionality to input  
 void AWanderer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)  
 {  
 	Super::SetupPlayerInputComponent(PlayerInputComponent);  
     
     UE_LOG(WandererLogCategory, Log, TEXT("set player input component"));  
 }  
 

WandererController.h:


  
 #pragma once  
     
 #include "CoreMinimal.h"  
 #include "AIController.h"  
 #include "Logging/LogMacros.h"  
 #include "Wanderer.h"  
 #include "WandererController.generated.h"  
     
 DECLARE_LOG_CATEGORY_EXTERN(WandererControllerLogCategory, Log, All);  
     
 /**  
  *   
  */  
 UCLASS()  
 class ERZSEBET_API AWandererController : public AAIController  
 {  
 	GENERATED_BODY()  
     
 private:  
     AWanderer *wanderer = 0;  
     
     virtual void BeginPlay() override;  
     
 public:  
     virtual void Possess(APawn * InPawn) override;  
     
     virtual void UnPossess() override;  
     
     virtual void Tick(float DeltaSeconds) override;  
 }; 

WandererController.cpp:


  
 #include "WandererController.h"  
 #include "EngineUtils.h"  
 #include "Engine/TargetPoint.h"  
     
 DEFINE_LOG_CATEGORY(WandererControllerLogCategory)  
     
     
 void AWandererController::BeginPlay() {  
     Super::BeginPlay();  
     
     UE_LOG(WandererControllerLogCategory, Log, TEXT("Hello, Wanderer!") );  
     
     for (TActorIterator<ATargetPoint> ActorItr(GetWorld()); ActorItr; ++ActorItr) {  
         // Same as with the Object Iterator, access the subclass instance with the * or -> operators.  
         ATargetPoint *point = *ActorItr;  
     
         UE_LOG(WandererControllerLogCategory, Log, TEXT("moving to: %s"), *(point->GetName()));  
         UE_LOG(WandererControllerLogCategory, Log, TEXT("moving to: %s"), *(point->GetFullName()));  
         UE_LOG(WandererControllerLogCategory, Log, TEXT("moving to: %s"), *(point->GetActorLocation().ToString()));  
     
         MoveToActor(point);  
         break;  
     }  
 }  
     
 void AWandererController::Possess(APawn * InPawn) {  
     Super::Possess(InPawn);  
     
     wanderer = Cast<AWanderer>(InPawn);  
     
     UE_LOG(WandererControllerLogCategory, Log, TEXT("possess: %s"), *(InPawn->GetName()));  
 }  
     
 void AWandererController::UnPossess() {  
     Super::UnPossess();  
     
     wanderer = 0;  
     
     UE_LOG(WandererControllerLogCategory, Log, TEXT("unpossess"));  
 }  
     
 void AWandererController::Tick(float DeltaSeconds) {  
     Super::Tick(DeltaSeconds);  
     
     //UE_LOG(WandererControllerLogCategory, Log, TEXT("Tick %f, Wanderer!"), DeltaSeconds );  
 }

the relevant log output is:

[2018.02.18-18.38.17:633] 67]WandererLogCategory: Wanderer created!
[2018.02.18-18.38.17:843] 67]WandererControllerLogCategory: possess: WandererBP_2
[2018.02.18-18.38.17:844] 67]WandererLogCategory: Wanderer begin play!
[2018.02.18-18.38.17:844] 67]WandererControllerLogCategory: Hello, Wanderer!
[2018.02.18-18.38.17:844] 67]WandererControllerLogCategory: moving to: TargetPoint4_14
[2018.02.18-18.38.17:844] 67]WandererControllerLogCategory: moving to: TargetPoint /Game/Levels/UEDPIE_0_BaseMap.BaseMap:PersistentLevel.TargetPoint4_14
[2018.02.18-18.38.17:844] 67]WandererControllerLogCategory: moving to: X=-410.000 Y=340.000 Z=20.000
[2018.02.18-18.38.17:844] 67]PIE: Play in editor start time for /Game/Levels/UEDPIE_0_BaseMap 25.845
[2018.02.18-18.38.19:261][230]WandererControllerLogCategory: unpossess
[2018.02.18-18.38.19:261][230]WandererControllerLogCategory: unpossess

which shows that indeed WandererController got possession of WandererBP, it issues a MoveToActor() call, but then WandererBP doesn’t move.

what am I doing wrong?

This may sound like a silly question, but you have setup nav-mesh right?

I lifted the code from the engine behind the blueprint node moveto to come up with the following.

TargeActor and Destination are parameters I pass in just like the engine code. I use Navigation Invoker so I don’t have to worry about a large nav mesh.

FAIMoveRequest MoveReq;
MoveReq.SetUsePathfinding(true);
MoveReq.SetAcceptanceRadius(AcceptanceRadius);
MoveReq.SetReachTestIncludesAgentRadius(bStopOnOverlap);
if (TargetActor)
{
    MoveReq.SetGoalActor(TargetActor);
    NextDestination = TargetActor;
}
else
{
    MoveReq.SetGoalLocation(Destination);
}

MoveReq.SetNavigationFilter(this-&gt;GetDefaultNavigationFilterClass());
FPathFollowingRequestResult ResultData = this-&gt;MoveTo(MoveReq);