這個教程是從UE4 Wiki上整理而來.
在C++中直接使用Interface大家應該很熟悉。只是簡單先定義一個個有虛函數的基類,然後在子類中實現相應的虛函數。像這樣的虛函數的基類一般概念上叫接口。那接下來看看UE4中怎樣在C++中定義接口的。
.h
#pragma once
#include "TargetInterface.generated.h"
UINTERFACE(MinimalAPI)
class UTargetInterface :
public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class ITargetInterface{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintImplementableEvent, meta=(FriendlyName = "On Interact"))
void OnInteract(bool bNewOpen);
virtual float GetHealth();
};
.cpp
#include "YourProject.h" #include "TargetInterface.h" UTargetInterface::UTargetInterface(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
// Give GetHealth a default implementation
float ITargetInterface::GetHealth(){
return 0.0f;
}
首先定義一個UTargetInterface這個是給引擎內部模塊用的,一般不會用到,但是要定義。
ITargetInterface是你要使用的類,你要聲明的函數接口都放在這裡面。如果是定義函數給C++用的,那麼你就直接按標准的C++聲明一個虛函數就OK了,然後你要實現這個接口的子類繼承ITargetInterface實現GetHealth函數就可以了。如果是給Blueprint用的,就要在函數前一行聲明的UFUNCTION內加上BlueprintImplementableEvent,這樣藍圖就可以實現這個接口了,藍圖中就像普通事件一樣實現。
.h
#pragma once #include "GameFramework/Actor.h" #include "TargetInterface.h" #include "NPCActor.generated.h" UCLASS() class MMWORLD_API NPCActor
: public AActor
, public ITargetInterface
{
GENERATED_BODY()
public:
AInteractiveTargetActor();
virtual float GetHealth() override;
protected:
float Health;
};
.cpp
#include "YourProject.h"
#include "NPCActor.h"
NPCActor::NPCActor()
{
Health = 100.0f;
}
float NPCActor::GetHealth()
{
return Health;
}
在C++代碼中這樣調用.如果是你知道Actor類的實際類型,直接調用就可以了。你不知道Actor的類型時候Interface才有實際的用處。
auto MyInterface = Cast<ITargetInterface>(ActorInstance);
if (MyInterface)
{
float ActorHealth = MyInterface->GetHealth();
}
但是這樣的接口藍圖中是無法使用的,藍圖完全無法知道它的存在。你可以再用Blueprint Function Library的方式再包裝一層,但是我覺得這不是很好。
在藍圖中實現Event接口:
之前的NPCActor因為已經繼承了ITargetInterface所以,你在藍圖編輯器裡可以直接實現OnInteract接口事件。
那如果你純藍圖的Actor怎麼辦。
進入藍圖編輯點Class Settings
if (ActorInstance->GetClass()->ImplementsInterface(ITargetInterface::StaticClass()))
{
ITargetInterface::Execute_OnInteract(ActorInstance, true);
}
ActorInstance->GetClass()->ImplementsInterface(ITargetInterface::StaticClass())) 是用來判斷這個Actor是否實現了TargetInterface,不管是在藍圖還是C++中都可以正確的判斷(但是只有BlueprintImplementableEvent和BlueprintNativeEvent(這個後面再介紹)的函數才可以被藍圖實現)。Execute_OnInteract執行藍圖事件,第一個參數是UObject對象(接口調用的執行目標對象),後面的參數就是OnInteract函數的參數。這個函數是UHT自動生成的。其實這個函數本質上就是調用的UObject的ProcessEvent,具體你可以看生成的代碼。(你到這個目錄下的文件看看就知道了,Yourproject\Intermediate\Build\Win64\Inc\Yourproject\Yourproject.generated.cpp,Yourproject是你的項目名稱)
最後一個問題,那如果想要這個函數接口既可以被C++實現又要被Blueprint實現怎麼辦?
你只要簡單的把BlueprintImplementableEvent改成BlueprintNativeEvent就可以了。
.h
#pragma once
#include "InteractionsInterface.generated.h"
UINTERFACE()
class MMWORLD_API UInteractionsInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class MMWORLD_API IInteractionsInterface
{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintNativeEvent)
void SwitchTurned(bool bNewOnOrOff, int32 CustomParam);
};
.cpp
#include "MMWorld.h"
#include "InteractionsInterface.h"
UInteractionsInterface::UInteractionsInterface(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
實現的Actor
.h
#pragma once
#include "GameFramework/Actor.h"
#include "InteractionsInterface.h"
#include "InteractiveTargetActor.generated.h"
UCLASS()
class MMWORLD_API AInteractiveTargetActor
: public AActor
, public IInteractionsInterface
{
GENERATED_BODY()
public:
AInteractiveTargetActor();
virtual void SwitchTurned_Implementation(bool bNewOnOrOff, int32 CustomParam) override;
UFUNCTION(BlueprintImplementableEvent, Category = Interactive)
void SwitchAllTurnedOnOrOff(bool bOnOrOff);
UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchTurned(int32 Index);
UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchAllTurnedOn();
UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchAllTurnedOff();
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (ClampMin = "1", ClampMax = "32", UIMin = "1", UIMax = "32"))
int32 NeedSwitchTurnedNum;
uint32 SwitchTurnedStates;
};
SwitchTurned在C++中要實現的函數是virtual void SwitchTurned_Implementation(bool bNewOnOrOff, int32 CustomParam) override; (BlueprintNativeEvent的函數名字_Implementation)。這個函數也是UHT自動生成的。
如果是你在Blueprint中是實現了SwitchTurned接口,那麼C++的實現就會被覆蓋隱藏掉。
那如果你的藍圖又要掉用C++接口實現怎麼辦?
UE4中沒有直接實現這樣的機制。但是你可以把SwitchTurned_Implementation實現提取出來一個新函數,然後把這個函數定義成UFUNCTION(BlueprintCallable, Category = Interactive),然後在藍圖中調用這個函數就解決了。
好了就介紹到這裡,第一次寫關於UE4的東西,不對的地方希望大家指正。希望這個對你有幫助。
參考例子:
https://github.com/henrya2/MMWorld
參考文章: