C++ only Interfaces... how can I get them to work?

So I currently have the following interface for certain classes, which contains the following:



UINTERFACE()
class BZGAME_API UBZGame_GameObjectInterface : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class IBZGame_GameObjectInterface
{
	GENERATED_IINTERFACE_BODY()

public:
	UFUNCTION(BlueprintNativeEvent, Category = "Game Object")
	void KillObject(FDamageEvent const& DamageEvent, AController* InInstigator, AActor* DamageCauser);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Game Object")
	USkeletalMeshComponent* GetRootMesh();

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Game Object")
	USkeletalMesh* GetFirstPersonMeshAsset();
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Game Object")
	UAnimBlueprint* GetFirstPersonAnimationAsset();

	// Accessors for common components
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Game Object")
	UBZGame_GameObjectComponent* GetGameObjectComponent();
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Game Object")
	UBZGame_UnitComponent* GetUnitComponent();
};


Now, NONE of those functions need to be implemented in Blueprint at any point in my game, and I don’t really want them to be. Since the interface is mostly just used as a way to access components or variables, I want to instead do this:



public:
	void KillObject(FDamageEvent const& DamageEvent, AController* InInstigator, AActor* DamageCauser);

	USkeletalMeshComponent* GetRootMesh() const;

	USkeletalMesh* GetFirstPersonMeshAsset() const;
	UAnimBlueprint* GetFirstPersonAnimationAsset() const;

	UBZGame_GameObjectComponent* GetGameObjectComponent() const;
	UBZGame_UnitComponent* GetUnitComponent() const;


Maybe they can’t be const, I don’t know - but in an ideal world they’d be FORCEINLINE AND Const.

I also want to be able to simply use Cast<> instead of having to do this horrible implementation that I need to do right now.



        // Ensure that the owning pawn implements the GameObject Interface
	ASSERTV(OwningPawn->GetClass()->ImplementsInterface(UBZGame_GameObjectInterface::StaticClass()), *FString::Printf(TEXT("Pawn %s doesn't implement the Game Object Interface!"), *GetNameSafe(GetOwner())));
	IBZGame_GameObjectInterface::Execute_KillObject(GetOwner(), DamageEvent, InInstigator, DamageCauser);


So long story short, HOW can I make my interface work this way? I still want to be able to create blueprints of these classes, but only to set defaults. None of this functionality needs to be overridden in BP.

Solved it. Used the UT code to work it out. Much neater!

I’ve had people message me about this, i haven’t done much interface programming. What did you do to fix it?

So this is what the new interface code looks like:



class IBZGame_GameObjectInterface
{
	GENERATED_IINTERFACE_BODY()

public:
	virtual void KillObject(FDamageEvent const& DamageEvent, AController* InInstigator, AActor* DamageCauser) PURE_VIRTUAL(IBZGame_GameObjectInterface::KillObject, );

	virtual USkeletalMeshComponent* GetRootMesh() const PURE_VIRTUAL(IBZGame_GameObjectInterface::GetRootMesh(), return nullptr;);

	virtual USkeletalMesh* GetFirstPersonMeshAsset() const PURE_VIRTUAL(IBZGame_GameObjectInterface::GetFirstPersonMeshAsset(), return nullptr;);
	virtual UAnimBlueprint* GetFirstPersonAnimationAsset() const PURE_VIRTUAL(IBZGame_GameObjectInterface::GetFirstPersonAnimationAsset(), return nullptr;);

	virtual UBZGame_GameObjectComponent* GetGameObjectComponent() const PURE_VIRTUAL(IBZGame_GameObjectInterface::GetGameObjectComponent(), return nullptr;);
	virtual UBZGame_UnitComponent* GetUnitComponent() const PURE_VIRTUAL(IBZGame_GameObjectInterface::GetUnitComponent(), return nullptr;);
};


Then an example of use from an inheriting class:



	/* Begin GOC Interface */
	virtual void KillObject(FDamageEvent const& DamageEvent, AController* InInstigator, AActor* DamageCauser) override;
	virtual USkeletalMeshComponent* GetRootMesh() const override { return GetMesh(); }
	virtual USkeletalMesh* GetFirstPersonMeshAsset() const override { return FirstPersonAsset; }
	virtual UAnimBlueprint* GetFirstPersonAnimationAsset() const override { return FirstPersonAnimAsset; }
	virtual UBZGame_GameObjectComponent* GetGameObjectComponent() const override { return GameObjectComponent; }
	virtual UBZGame_UnitComponent* GetUnitComponent() const override { return UnitComponent; }
	// End GOC Interface	


And using it:



		IBZGame_GameObjectInterface* Collector = Cast<IBZGame_GameObjectInterface>(OtherActor);
		if (Collector)
		{
			if (CanObjectCollect(Collector))
			{
				CollectPowerUp(Collector);
			}
			else
			{
				RejectPowerUp();
			}
		}


So one thing I’ve learned since, is that you CAN pass pointers to the interface object into functions etc, but they CANNOT be UFUNCTION() (even an empty macro). Not entirely sure why, but you can use them like this:



void ABZGame_PowerUp::CollectPowerUp(IBZGame_GameObjectInterface* InGameObject)
{
	if (Role == ROLE_Authority)
	{
		DestroyPowerup();
	}
}


I’m yet to discover any ill-effects using this method, but so far it’s been fine.

1 Like