Hello Everyone, I have a question about Pawn. I want to make an AI that from Pawn Class not from Character Class. I want to make an AI with Pawn class because I need to spawn big number of Pawn in game but only need a basic movement only. So I make a basic pawn and I create a simple movement component for the pawn.
// This is Header File
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PawnMovementComponent.h"
#include "CustomPawnMovementComponent.generated.h"
/**
*
*/
UCLASS()
class MEDIEVALPANDEMIC_API UCustomPawnMovementComponent : public UPawnMovementComponent
{
GENERATED_BODY()
public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
// Nav Movement Component Function
virtual void RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed) override;
virtual bool CanStartPathFollowing() const override;
virtual bool CanStopPathFollowing() const override;
virtual float GetPathFollowingBrakingDistance(float MaxSpeed) const override;
};
// This is CPP File
#include "CustomPawnMovementComponent.h"
void UCustomPawnMovementComponent::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if(!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime)){return;}
FVector DesiredMovement = ConsumeInputVector().GetClampedToMaxSize(1.f);
if(!DesiredMovement.IsNearlyZero())
{
FHitResult Hit;
SafeMoveUpdatedComponent(DesiredMovement, UpdatedComponent->GetComponentRotation(), true, Hit);
if(Hit.IsValidBlockingHit())
{
SlideAlongSurface(DesiredMovement, 1.f - Hit.Time, Hit.Normal, Hit);
}
}
}
void UCustomPawnMovementComponent::RequestDirectMove(const FVector& MoveVelocity, bool bForceMaxSpeed)
{
Super::RequestDirectMove(MoveVelocity, bForceMaxSpeed);
}
bool UCustomPawnMovementComponent::CanStartPathFollowing() const
{
return Super::CanStartPathFollowing();
}
bool UCustomPawnMovementComponent::CanStopPathFollowing() const
{
return !IsFalling();
}
float UCustomPawnMovementComponent::GetPathFollowingBrakingDistance(float MaxSpeed) const
{
if(bUseFixedBrakingDistanceForPaths)
{
return FixedPathBrakingDistance;
}
// const float Braking = 16384.f;
//
// float BrakingDistance =
return MaxSpeed;
}
PAWN CLASS
// Header File
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "PawnTest.generated.h"
UCLASS()
class MEDIEVALPANDEMIC_API APawnTest : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
APawnTest();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// OnConstruction
virtual void OnConstruction(const FTransform& Transform) override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
/** Capsule Component */
UPROPERTY(EditDefaultsOnly, Category = "Components")
class UCapsuleComponent* CapsuleComponent;
/** Skeletal Mesh Component */
UPROPERTY(EditDefaultsOnly, Category = "Components")
class USkeletalMeshComponent* SkeletalMeshComponent;
/** Arrow Component */
UPROPERTY(EditDefaultsOnly, Category = "Components")
class UArrowComponent* ArrowComponent;
/** AI Controller */
UPROPERTY(EditDefaultsOnly, Category = "Controller")
class AEnemyAIController* EnemyAI;
/** Boolean for handling auto compute mesh location on Capsule Bottom */
UPROPERTY(EditDefaultsOnly, Category = "Constructions")
bool bAutoComputeMeshZLocation;
/** Movement Component */
UPROPERTY(VisibleAnywhere, Category = "Components")
class UCustomPawnMovementComponent* MovementComponent;
/** Function */
/** Set Mesh Location To Bottom Capsule */
void SetMeshLocationToBottomOfCapsule();
/** Set Mesh Rotation To Right Rotation */
void SetMeshRotationToRightRotation();
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "PawnTest.h"
#include "CustomPawnMovementComponent.h"
#include "EnemyAIController.h"
#include "Components/ArrowComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/FloatingPawnMovement.h"
#include "Kismet/KismetSystemLibrary.h"
// Sets default values
APawnTest::APawnTest()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CapsuleComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule Component"));
RootComponent = CapsuleComponent;
CapsuleComponent->SetCapsuleSize(34.f, 90.f);
SkeletalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Skeletal Mesh"));
SkeletalMeshComponent->SetupAttachment(GetRootComponent());
ArrowComponent = CreateDefaultSubobject<UArrowComponent>(TEXT("Arrow"));
ArrowComponent->SetupAttachment(GetRootComponent());
MovementComponent = CreateDefaultSubobject<UCustomPawnMovementComponent>(TEXT("Movement Component"));
MovementComponent->UpdatedComponent = GetRootComponent();
bAutoComputeMeshZLocation = false;
SetMeshRotationToRightRotation();
SetMeshLocationToBottomOfCapsule();
}
// Called when the game starts or when spawned
void APawnTest::BeginPlay()
{
Super::BeginPlay();
CapsuleComponent->SetCollisionProfileName(TEXT("Pawn"));
CapsuleComponent->CanCharacterStepUpOn = ECanBeCharacterBase::ECB_No;
SkeletalMeshComponent->SetCollisionProfileName(TEXT("CharacterMesh"));
// FLatentActionInfo Info;
// UKismetSystemLibrary::Delay(GetWorld(), 3.f, Info);
EnemyAI = Cast<AEnemyAIController>(GetController());
if(EnemyAI)
{
UE_LOG(LogTemp, Warning, TEXT("Move"));
EnemyAI->MoveToLocation(FVector(0.f, 0.f, 259.f));
}
}
void APawnTest::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
if(bAutoComputeMeshZLocation)
{
SetMeshLocationToBottomOfCapsule();
}
}
// Called every frame
void APawnTest::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
EnemyAI = Cast<AEnemyAIController>(GetController());
if(EnemyAI)
{
UE_LOG(LogTemp, Warning, TEXT("Move"));
EnemyAI->MoveToCastleGate();
}
}
// Called to bind functionality to input
void APawnTest::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void APawnTest::SetMeshLocationToBottomOfCapsule()
{
if(SkeletalMeshComponent)
{
FVector NewLoc = FVector(0.f);
NewLoc.Z -= CapsuleComponent->GetUnscaledCapsuleHalfHeight();
SkeletalMeshComponent->SetRelativeLocation(NewLoc);
}
}
void APawnTest::SetMeshRotationToRightRotation()
{
if(SkeletalMeshComponent)
{
SkeletalMeshComponent->SetRelativeRotation(FRotator(0.f, -90.f, 0.f));
}
}
I already make the Custom Pawn Movement Component like that code, but I dont know why, the Pawn do not want to move in the level. even that my AI Controller is valid in the pawn class and there is a navmesh bound in the level already. I also tested it using FloatingPawnMovement and it is work but the pawn is floating not walking. So How do you guys think I should do? Thank you very much!