Hi, I hope someone can assist with this as I’m struggling to figure out where I have gone wrong.
Mechanic I’m trying to acheive:
Upon seeing (I am using a sweep - geom trace) an object that can be used for hiding (I created a custom trace channel for “hiding place” objects), the character moves to the location and hides.
What works:
The sweep works perfectly, returning the hit location of the hiding place. The character is possessed by the AIController and moves to the stored hit location.
Key Info:
I have setup a custom class called RAIController.
The issues:
There appears to be two instances of the AIController that appears in the Outliner. The second instance is the one that possesses the character. The other doesn’t register as a valid AIController and that is why a second is created.
The second AIController that possesses the character moves it to the correct location but when the PlayerController is meant to take back possession, that does not happen.
When the player reaches the hiding spot, the camera and boom are meant to track in tight on the characters face. This was working before I implemented the AIController possession but doesn’t work now.
Here is the code for all AI functions:
RAIController.h
#pragma once
#include "CoreMinimal.h"
#include "AIController.h"
#include "RAIController.generated.h"
/**
*
*/
UCLASS()
class RUSALKA_API ARAIController : public AAIController
{
GENERATED_BODY()
public:
virtual void OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result) override;
};
RAIController.cpp
#include "Characters/RAIController.h"
#include "Characters/RCharacter.h"
#include "Navigation/PathFollowingComponent.h"
#include "Macros/RMacros.h"
void ARAIController::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
{
Super::OnMoveCompleted(RequestID, Result);
if (Result.Code == EPathFollowingResult::Success)
{
ARCharacter* Hiker = Cast<ARCharacter>(GetPawn());
if (Hiker)
{
Hiker->bMoveCompleted = true;
Hiker->PossessByPlayer();
Hiker->Alpha = 0.0f;
Hiker->bIsHiding = true;
Hiker->SetRPlayerState(EPlayerState::EPS_Hiding);
Hiker->SetRActionState(EActionState::EAS_Standing);
PRINT(12, TEXT("Move has completed!"));
}
}
}
RCharacter.h
void PossessByPlayer();
void PossessByAI();
void CheckForAIController();
void OnMoveCompleted();
virtual void PossessedBy(AController* NewController) override;
UPROPERTY()
ARAIController* AIControllerInstance;
RCharacter.cpp
ARCharacter::ARCharacter()
{
AIControllerClass = ARAIController::StaticClass();
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
AIControllerInstance = nullptr;
}
void ARCharacter::BeginPlay()
{
Super::BeginPlay();
AIControllerInstance = Cast<ARAIController>(GetController());
if (AIControllerInstance)
{
PRINT(-1, TEXT("AIController is initialized in BeginPlay"));
}
else
{
GetWorld()->GetTimerManager().SetTimerForNextTick(this, &ARCharacter::CheckForAIController);
}
if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(RPlayerMappingContext, 0);
}
}
}
void ARCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
AIControllerInstance = Cast<ARAIController>(NewController);
if (AIControllerInstance)
{
PRINT(-1, TEXT("AIController has possessed the character"));
}
}
void ARCharacter::TakingCover()
{
// this is a call back for when the Q-Key is pressed, which starts the taking cover and then hiding.
UE_LOG(LogTemp, Warning, TEXT("Cover Location found: %s"), bHasHit ? TEXT("true") : TEXT("False"));
bIsTakingCover = !bIsTakingCover;
UE_LOG(LogTemp, Warning, TEXT("Taking Cover is: %s"), bIsTakingCover ? TEXT("true") : TEXT("False"));
if (bHasHit && bIsTakingCover)
{
RActionState = EActionState::EAS_TakingCover;
MoveToCover();
}
else
{
RPlayerState = EPlayerState::EPS_Idle;
RActionState = EActionState::EAS_Standing;
}
}
void ARCharacter::PossessByPlayer()
{
if (GetRPlayerCamera())
{
StoredCameraLocation = GetRPlayerCamera()->GetRelativeLocation();
StoredCameraRotation = GetRPlayerCamera()->GetRelativeRotation();
StoredFieldOfView = GetRPlayerCamera()->FieldOfView;
StoredSpringArmLength = GetRPlayerBoom()->TargetArmLength;
}
PRINT(-1, TEXT("PossessByPlayer has been called"))
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController)
{
PlayerController->Possess(this);
GetRPlayerBoom()->bUsePawnControlRotation = true;
GetRPlayerCamera()->bUsePawnControlRotation = false;
}
if (GetRPlayerCamera())
{
GetRPlayerCamera()->SetRelativeLocation(StoredCameraLocation);
GetRPlayerCamera()->SetRelativeRotation(StoredCameraRotation);
GetRPlayerCamera()->FieldOfView = StoredFieldOfView;
GetRPlayerBoom()->TargetArmLength = StoredSpringArmLength;
}
RPlayerState = EPlayerState::EPS_Idle;
RActionState = EActionState::EAS_Standing;
}
void ARCharacter::PossessByAI()
{
if (GetRPlayerCamera())
{
StoredCameraLocation = GetRPlayerCamera()->GetRelativeLocation();
StoredCameraRotation = GetRPlayerCamera()->GetRelativeRotation();
StoredFieldOfView = GetRPlayerCamera()->FieldOfView;
StoredSpringArmLength = GetRPlayerBoom()->TargetArmLength;
}
if (!AIControllerInstance)
{
AIControllerInstance = Cast<ARAIController>(GetController());
}
if (!AIControllerInstance && GetWorld())
{
PRINT(-1, TEXT("No existing AI Controller found. Spawning a new one"));
AIControllerInstance = GetWorld()->SpawnActor<ARAIController>(AIControllerClass, GetActorLocation(), GetActorRotation());
if (AIControllerInstance)
{
AIControllerInstance->Possess(this);
}
else
{
PRINT(-1, TEXT("Failed to spawn AI Controller."));
return;
}
}
else if (AIControllerInstance)
{
AIControllerInstance->Possess(this);
}
GetRPlayerBoom()->bUsePawnControlRotation = false;
GetRPlayerCamera()->bUsePawnControlRotation = true;
if (GetRPlayerCamera())
{
GetRPlayerCamera()->SetRelativeLocation(StoredCameraLocation);
GetRPlayerCamera()->SetRelativeRotation(StoredCameraRotation);
GetRPlayerCamera()->FieldOfView = StoredFieldOfView;
GetRPlayerBoom()->TargetArmLength = StoredSpringArmLength;
}
}
void ARCharacter::CheckForAIController()
{
if (AIControllerInstance)
{
PRINT(-1, TEXT("AIController is born (delayed check)"))
}
}