Suppose I want to create an AI class in code that will be used to control a pawn, but I want my designers to be able to modify the behavior using blueprints for rapid iterations.
Suppose I have this in MyProjectBaseAI.h:
#pragma once
#include "EngineMinimal.h"
#include "GameFramework/Actor.h"
#include "MyProjectBaseAI.generated.h"
UCLASS()
class MYPROJECT_API AMyProjectBaseAI : AActor
{
GENERATED_BODY()
public:
AMyProjectBaseAI(const FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
void SetGoalPosition(FVector pos);
virtual void DetermineGoalPosition(int32 stateData1, int32 stateData2) = 0;
private:
FVector goalPosition;
};
I would like to make this class abstract and have a blueprint able to implement DetermineGoalPosition(...);
to call SetGoalPosition(FVector pos)
depending on their design of the AI.
Then, how can the designers set the implementing class in the inspector so that my C++ code can instantiate it? Suppose I have a class that wants to instantiate the implementing class like this (currently using base class):
AMyProjectBaseAI* ai = World->SpawnActor<AMyProjectBaseAI>(...);
Use the Abstract
and Blueprintable
specifiers in UCLASS
to mark the class as abstract and blueprintable (although, when you are inheriting from AActor
or another blueprintable class, the Blueprintable
specifier is redundant).
Use BlueprintImplementableEvent
in a UFUNCTION
specifier for DetermineGoalPosition
. This allows blueprints to implement the function.
Also, do not declare the function as virtual, per Unreal's standard since ver 4.8:
New: Removed "virtual" keyword from several engine-level BlueprintImplementableEvents to conform to the new "BlueprintImplementableEvents should not be virtual" standard.
Use the BlueprintCallable
property in a UFUNCTION
specifier for SetGoalPosition
. This allows the function to be called from a blueprint.
#pragma once
#include "EngineMinimal.h"
#include "GameFramework/Actor.h"
#include "MyProjectBaseAI.generated.h"
UCLASS(Abstract, Blueprintable)
class MYPROJECT_API AMyProjectBaseAI : AActor
{
GENERATED_BODY()
public:
AMyProjectBaseAI(const FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
UFUNCTION(BlueprintCallable)
void SetGoalPosition(FVector pos);
UFUNCTION(BlueprintImplementableEvent)
void DetermineGoalPosition(int32 stateData1, int32 stateData2);
private:
FVector goalPosition;
};
Then in the header of the class you would like to set the implementing class in the inspector, have a public TSubclassOf<AMyProjectBaseAI>
variable with the EditAnywhere
specifier (or EditDefaultsOnly
or EditInstanceOnly
if the subclass should be set only at the blueprint or instance level in the editor):
public:
UPROPERTY(EditAnywhere)
TSubclassOf<AMyProjectBaseAI> AIImplementationClass;
And then where you instantiate it, simply use AIImplementationClass
as the class:
AMyProjectBaseAI* ai = World->SpawnActor<AMyProjectBaseAI>(AIImplementationClass);