Issues With Setting-Up UInterpToMovementComponent

So in my project (known as Quest: To Be Defined), I set-up a class in C++, for which there is then a Blueprint Class that inherits from this native class (allowing one to choose certain components of this entity).

This class is known as the ‘CombatAdmin’ (for a Character in my project, which follows the Player from where the game begins. As I had intended for the CombatAdmin to fly above the player, their class inherits from AActor as opposed to ACharacter).

This class is defined as such (CombatAdmin.h):

/**
	This class is for another of the Player's 'Companions'.
*/

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
#include "Runtime/Engine/Classes/Components/InterpToMovementComponent.h"
#include "QuestToBeDefinedCharacter.h"
#include "CombatAdmin.generated.h"

UCLASS()
class QUESTTOBEDEFINED_API ACombatAdmin : public AActor
{
	GENERATED_BODY()
	
public:	

	/** For initialisation */
	ACombatAdmin();

	/** 
		To reference the static mesh assets to use. 
		(EditAnywhere and BlueprintReadWrite flags used
		instead of EditDefaultsOnly and BlueprintReadOnly,
		as these flags allow one to choose the assets
		to use in the editor, but this change is not reflected
		upon beginning play).
	*/
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StaticMeshReferences)
	UStaticMesh* CoreMeshReference;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = StaticMeshReferences)
	UStaticMesh* WingMeshReference;

private:

	// Functions:

	/** Initialise components before starting play */
	virtual void BeginPlay() override;

	/** Handle updates to the CombatAdmin */
	virtual void Tick(float DeltaSeconds)override;

	/** 
		Move to the Player's current position.

		// Not present for now:
		@Param: float DeltaTime: From Tick(), to
		use in Vector2DInterpTo().
	*/
	void UpdatePlayerPosition();

	/** Adjust the control points for the new Player's position */
	void UpdateControlPoints();

	// Properties:

	// Core components:
	UStaticMeshComponent* BodyCore;
	UStaticMeshComponent* LeftWing;
	UStaticMeshComponent* RightWing;

	/** For handling movement */
	UInterpToMovementComponent* PrimaryMovementComponent;
	
	/** The default position to interperlate to (above the Player Character) */
	FVector DefaultTargetPosition;

	/** To refer to the Player Character's location */
	AQuestToBeDefinedCharacter* PlayerCharacterReference;
	
	// Constant values:
	const float DEFAULT_FLYING_HEIGHT = 1000.0f;
	const float DEFAULT_MOVEMENT_TIME = 3.0f;
};

The implementation of this class is as follows (CombatAdmin.cpp):

// Fill out your copyright notice in the Description page of Project Settings.

#include "CombatAdmin.h"
#include "Engine.h"

// Perform pre-game initialisation:
ACombatAdmin::ACombatAdmin()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// Initialise the components:

	BodyCore = CreateDefaultSubobject<UStaticMeshComponent>(FName("BodyCore"));
	LeftWing = CreateDefaultSubobject<UStaticMeshComponent>(FName("LeftWing"));
	RightWing = CreateDefaultSubobject<UStaticMeshComponent>(FName("RightWing"));
	PrimaryMovementComponent = CreateDefaultSubobject<UInterpToMovementComponent>(FName("PrimaryMovementComponent"));
}

// Perform initialisation that can only take place after play begins:
void ACombatAdmin::BeginPlay()
{
	Super::BeginPlay();

	BodyCore->SetStaticMesh(CoreMeshReference);

	LeftWing->SetStaticMesh(WingMeshReference);
	LeftWing->AttachToComponent(BodyCore, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
	LeftWing->SetRelativeLocationAndRotation(FVector(5.0f, -50.0f, 45.0f), 
		FRotator(0.0f, 90.0f, 0.0f).Quaternion());
	
	RightWing->SetStaticMesh(WingMeshReference);
	RightWing->AttachToComponent(BodyCore, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
	RightWing->SetRelativeLocationAndRotation(FVector(5.0f, 50.0f, 45.0f), 
		FRotator(0.0f, -90.0f, 0.0f).Quaternion());

	// To move to the default target position:
	/**
	PrimaryMovementComponent->bAllowConcurrentTick = true;
	PrimaryMovementComponent->bAutoRegisterUpdatedComponent = true;
	PrimaryMovementComponent->bAutoRegister = true;
	PrimaryMovementComponent->bAutoActivate = true;
	*/
	PrimaryMovementComponent->BehaviourType = EInterpToBehaviourType::OneShot;
	
	//PrimaryMovementComponent->bTickInEditor = true;
	UpdatePlayerPosition();

	//PrimaryMovementComponent->ConstrainLocationToPlane()

	/** 
		This causes the CombatAdmin to move to 
		the Player's starting location (1000 units above), but no further.
	*/
	PrimaryMovementComponent->AddControlPointPosition(GetActorLocation(), false);
	PrimaryMovementComponent->AddControlPointPosition(DefaultTargetPosition, false);
	PrimaryMovementComponent->Duration = DEFAULT_MOVEMENT_TIME;		
	PrimaryMovementComponent->Activate();
}

void ACombatAdmin::Tick(float DeltaSeconds)
{
	if (PlayerCharacterReference)
	{
		if (DefaultTargetPosition != (PlayerCharacterReference->GetActorLocation()
			+ FVector(0.0f, 0.0f, DEFAULT_FLYING_HEIGHT)))
		{
			UpdatePlayerPosition();
		}
	}	
}

void ACombatAdmin::UpdatePlayerPosition()
{
	if (!PlayerCharacterReference)
	{
		PlayerCharacterReference = Cast<AQuestToBeDefinedCharacter>(UGameplayStatics::GetPlayerCharacter(this, 0));
	}

	// For the new initial point:
	UpdateControlPoints();

	// Then get the new position:
	DefaultTargetPosition = PlayerCharacterReference->GetActorLocation() + FVector(0.0f, 0.0f, DEFAULT_FLYING_HEIGHT);
	PrimaryMovementComponent->AddControlPointPosition(DefaultTargetPosition, false);
}

// For the Player's new position:
void ACombatAdmin::UpdateControlPoints()
{
	PrimaryMovementComponent->ControlPoints.Empty();
	PrimaryMovementComponent->AddControlPointPosition(DefaultTargetPosition, false);
}

/**
	This is what allows the CombatAdmin to move to
	the Player's initial position from their starting
	position (but after this, they then stop):
*/

//// Fill out your copyright notice in the Description page of Project Settings.
//
//#include "CombatAdmin.h"
//#include "Engine.h"
//
//// Perform pre-game initialisation:
//ACombatAdmin::ACombatAdmin()
//{
//	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
//	PrimaryActorTick.bCanEverTick = true;
//
//	// Initialise the components:
//
//	BodyCore = CreateDefaultSubobject<UStaticMeshComponent>(FName("BodyCore"));
//	LeftWing = CreateDefaultSubobject<UStaticMeshComponent>(FName("LeftWing"));
//	RightWing = CreateDefaultSubobject<UStaticMeshComponent>(FName("RightWing"));
//	PrimaryMovementComponent = CreateDefaultSubobject<UInterpToMovementComponent>(FName("PrimaryMovementComponent"));
//}
//
//// Perform initialisation that can only take place after play begins:
//void ACombatAdmin::BeginPlay()
//{
//	Super::BeginPlay();
//
//	BodyCore->SetStaticMesh(CoreMeshReference);
//
//	LeftWing->SetStaticMesh(WingMeshReference);
//	LeftWing->AttachToComponent(BodyCore, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
//	LeftWing->SetRelativeLocationAndRotation(FVector(5.0f, -50.0f, 45.0f),
//		FRotator(0.0f, 90.0f, 0.0f).Quaternion());
//
//	RightWing->SetStaticMesh(WingMeshReference);
//	RightWing->AttachToComponent(BodyCore, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
//	RightWing->SetRelativeLocationAndRotation(FVector(5.0f, 50.0f, 45.0f),
//		FRotator(0.0f, -90.0f, 0.0f).Quaternion());
//
//	// To move to the default target position:
//	/**
//	PrimaryMovementComponent->bAllowConcurrentTick = true;
//	PrimaryMovementComponent->bAutoRegisterUpdatedComponent = true;
//	PrimaryMovementComponent->bAutoRegister = true;
//	PrimaryMovementComponent->bAutoActivate = true;
//	PrimaryMovementComponent->BehaviourType = EInterpToBehaviourType::PingPong;
//	*/
//	//PrimaryMovementComponent->bTickInEditor = true;
//	UpdatePlayerPosition();
//
//	//PrimaryMovementComponent->ConstrainLocationToPlane()
//
//	/**
//	This causes the CombatAdmin to move to
//	the Player's starting location (1000 units above), but no further.
//	*/
//	PrimaryMovementComponent->AddControlPointPosition(GetActorLocation(), false);
//	PrimaryMovementComponent->AddControlPointPosition(DefaultTargetPosition, false);
//	PrimaryMovementComponent->Duration = DEFAULT_MOVEMENT_TIME;
//	PrimaryMovementComponent->Activate();
//}
//
//void ACombatAdmin::Tick(float DeltaSeconds)
//{
//	if (PlayerCharacterReference)
//	{
//		if (DefaultTargetPosition != (PlayerCharacterReference->GetActorLocation()
//			+ FVector(0.0f, 0.0f, DEFAULT_FLYING_HEIGHT)))
//		{
//			UpdatePlayerPosition();
//		}
//	}
//}
//
//void ACombatAdmin::UpdatePlayerPosition()
//{
//	if (!PlayerCharacterReference)
//	{
//		PlayerCharacterReference = Cast<AQuestToBeDefinedCharacter>(UGameplayStatics::GetPlayerCharacter(this, 0));
//	}
//
//	DefaultTargetPosition = PlayerCharacterReference->GetActorLocation() + FVector(0.0f, 0.0f, DEFAULT_FLYING_HEIGHT);
//	PrimaryMovementComponent->AddControlPointPosition(DefaultTargetPosition, false);
//}

Note that the implementation that is ‘commented-out’ (with ‘//’ preceding each line of code), causes the CombatAdmin to move to the Player’s initial location, but remain there, even if the Player moves from their spawn point.

For the implementation that is not ‘commented-out’, the CombatAdmin moves to and remains at another location, with the co-ordinates for such, shown in the screenshot below:

211654-combatadmingotoposition.png

For reference, the Player’s spawn point is located at (X=19190.000000,Y=17580.000000,Z=302.000000), with a rotation of (Pitch=0.000000,Yaw=-129.999451,Roll=0.000000).

Even if one looks towards that location as the Player Character, they are not able to see the CombatAdmin at all.

To the point then, I would simply want the CombatAdmin to linearly-interpolate to the Player’s current position, whenever the Player moves. I was able to get this working with an old Blueprint for the CombatAdmin, but it seems as though the C++ implementation for such is not as straight forward.

Please then, could anyone provide assistance with this issue? I would greatly appreciate this, as I have found myself stuck on this issue for several days now.

Would anyone have any pointers at all? Even if it might not resolve the issue, it could help me to track down the issue.

It has been a while, but I have found a work around (code sample below), so this issue has been resolved:

// Make sure to call GetWorld() to get DeltaTimeSeconds:
void ACombatAdmin::ExecuteInterpolateMovement()
{
	// Interp to the current location of the Player:
	FVector CurrentLocation = GetActorLocation();
	float WorldDeltaTime = GetWorld()->DeltaTimeSeconds;
	FVector MovementStep = FMath::VInterpTo(CurrentLocation, DefaultTargetPosition, WorldDeltaTime,
		DefaultMovementTime);	
	FRotator RotationStep = UKismetMathLibrary::FindLookAtRotation(CurrentLocation, DefaultTargetPosition);
	SetActorLocationAndRotation(MovementStep, RotationStep);
}