接口

创建和实现接口的引用。

Windows
MacOS
Linux

接口类有助于确保一组(可能)不相关的类实现一组通用函数。在某些游戏功能可能被大量复杂而不同的类共享的情况下,这非常有用。例如,某个游戏可能有这样一个系统,依靠该系统输入一个触发器体积可以激活陷阱、警告敌人或向玩家奖励点数。这可以通过针对陷阱、敌人和点数奖励器执行"ReactToTrigger"函数来实现。然而,陷阱可能派生自"AActor",敌人可能派生自专门的"APawn"或"ACharacter"子类,点数奖励可能派生自"UDataAsset"。所有这些类都需要共享功能,但它们没有除"UObject"之外的共同上级。在这种情况下,推荐使用接口。

接口声明

声明接口类与声明普通的虚幻类相似,但仍有两个主要区别。首先,接口类使用UINTERFACE宏而不是UCLASS宏,且直接从"UInterface"而不是"UObject"继承。

UINTERFACE([specifier, specifier, ...], [meta(key=value, key=value, ...)])
class UClassName : public UInterface
{
    GENERATED_BODY()
};

其次,UINTERFACE类不是实际的接口;它是一个空白类,它的存在只是为了向虚幻引擎反射系统确保可见性。将由其他类继承的实际接口必须具有相同的类名,但是开头字母"U"必须改为"I"。

在您的.h文件(例如"ReactToTriggerInterface.h")中:

ReactToTriggerInterface.h

#pragma once

#include "ReactToTriggerInterface.generated.h"

UINTERFACE(MinimalAPI, Blueprintable)
class UReactToTriggerInterface : public UInterface
{
    GENERATED_BODY()
};

class IReactToTriggerInterface
{    
    GENERATED_BODY()

public:
    /** 在此处添加接口函数声明 */
};

"前缀为U(U-prefixed)"的类不需要构造函数或任何其他函数,而"前缀为I(I-prefixed)"的类将包含所有接口函数,且此类实际上将被您的其他类继承。

如果您想要让蓝图实现此接口,则需要"Blueprintable"说明符。

接口说明符

接口说明符

含义

"BlueprintType"

将该类公开为可用于蓝图中的变量的类型。

"DependsOn=(ClassName1, ClassName2, ...)"

所有列出的类都将在该类之前编译。ClassName必须在同一个(或上一个)包中指定一个类。多个依赖性类可以使用以逗号分隔的单个"DependsOn"行来指定,也可以使用单个"DependsOn"行为每个类指定。当一个类使用在另一个类中声明的结构体或枚举时,这一点非常重要,因为编译器只知道它已经编译的类中的内容。

"MinimalAPI"

仅导致该类的类型信息被导出以供其他模块使用。您可以向该类转换,但不能调用该类的函数(内联方法除外)。对于不需要其所有函数在其他模块中均可供访问的类,通过不导出这些类的所有内容,这可以缩短编译时间。

在C++中实现接口

若要在一个新的类中使用您的接口,只需从"前缀为I(I-prefixed)"的接口类继承(除了您正在使用的任何基于"UObject"的类)即可。

Trap.h

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ReactToTriggerInterface.h"
#include "Trap.generated.h"

UCLASS(Blueprintable, Category="MyGame")
class ATrap : public AActor, public IReactToTriggerInterface
{
    GENERATED_BODY()

public:
    /** Add interface function overrides here. */
}

声明接口函数

有几种方法可以在接口中声明函数,由环境决定能够实现或调用哪种方法。所有方法都必须在"前缀为I(I-prefixed)"的类中为接口声明,而且必须为 public,以便对外部的类可见。

仅C++的接口函数

可以在接口的头文件中声明一个不带 UFUNCTION 说明的虚拟C++函数。这些函数必须为虚拟的,以便在实现接口的类中覆盖它们。

ReactToTrigger.h

public:
virtual bool ReactToTrigger();

然后,可以在头文件本身或接口的 .cpp 文件中提供一个默认的实现。

ReactToTrigger.cpp

bool IReactToTriggerInterface::ReactToTrigger()
{
    return false;
}

当在一个Actor类中实现接口后,可以创建并实现一个针对该类的覆盖。

Trap.h

public:
virtual bool ReactToTrigger() override;

Trap.cpp

bool ATrap::ReactToTrigger()
{
    return false;
}

但是,这些C++接口函数对蓝图不可见。

蓝图可调用接口函数

要创建蓝图可调用的接口函数,必须在带 BlueprintCallable 说明符的函数声明中提供一个 UFUNCTION 宏。还必须使用 BlueprintImplementableEventBlueprintNativeEvent 说明,而且函数不能为虚拟的。

ReactToTrigger.h

public:
/**只能在蓝图中实现的React To Trigger版本。*/
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category=Trigger Reaction)
bool ReactToTrigger();

ReactToTrigger.h

public:
/**可以在C++或蓝图中实现的React To Trigger版本。*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category=Trigger Reaction)
bool ReactToTrigger();

BlueprintCallable

引用实现接口的对象的C++或蓝图可以调用使用 BlueprintCallable 说明符的函数。

![](ReactToTriggerCall.png)(w:500)

BlueprintImplementableEvent

使用 BlueprintImplementableEvent 的函数不能在C++中被腹杆,但可以任何实现或继承接口的蓝图类中被覆盖。

![](ReactToTrigger_BlueprintImplementable.png)(w:700)

BlueprintNativeEvent

在C++中,可通过覆盖一个同名函数来实现使用 BlueprintNativeEvent 的函数,但要在末尾添加上后缀 _Implementation

Trap.h

public:
bool ReactToTrigger_Implementation() override;

Trap.cpp

bool ATrap::ReactToTrigger_Implementation() const
{
    return false;
}

该说明符还允许在蓝图中覆盖实现。

确定类是否实现了接口

为了与实现接口的C++和蓝图类兼容,可以使用以下任意函数:

bool bIsImplemented = OriginalObject->GetClass()->ImplementsInterface(UReactToTriggerInterface::StaticClass()); // 如果OriginalObject实现了UReactToTriggerInterface,则bisimplemated将为true。

bIsImplemented = OriginalObject->Implements<UReactToTriggerInterface>(); // 如果OriginalObject实现了UReactToTrigger,bIsImplemented将为true。

IReactToTriggerInterface* ReactingObject = Cast<IReactToTriggerInterface>(OriginalObject); // 如果OriginalObject实现了UReactToTriggerInterface,则ReactingObject将为非空。

如果"StaticClass"函数在"前缀为I(I-prefixed)"的类中没有实现,尝试在"前缀为U(U-prefixed)"的类上使用"转换(Cast)"将失败,代码将无法编译。

转换到其他虚幻类型

虚幻引擎的转换系统支持从一个接口转换到另一个接口,或者在适当的情况下,从一个接口转换到一个虚幻类型。

IReactToTriggerInterface* ReactingObject = Cast<IReactToTriggerInterface>(OriginalObject); // 如果接口被实现,则ReactingObject将为非空。

ISomeOtherInterface* DifferentInterface = Cast<ISomeOtherInterface>(ReactingObject); // 如果ReactingObject为非空而且还实现了ISomeOtherInterface,则DifferentInterface将为非空。

AActor* Actor = Cast<AActor>(ReactingObject); // 如果ReactingObject为非空且OriginalObject为AActor或AActor派生的类,则Actor将为非空。

蓝图可实现类

如果您想要蓝图能够实现此接口,则必须使用"Blueprintable"元数据说明符。蓝图类要覆盖的每个接口函数都必须是"BlueprintNativeEvent"或"BlueprintImplementableEvent"。标记为"BlueprintCallable"的函数仍然可以被调用,但不能被覆盖。您将无法从蓝图访问所有其他函数。

Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback