UFunction 是虚幻引擎(UE)反射系统可识别的C++函数。UObject
或蓝图函数库可将成员函数声明为UFunction,方法是将 UFUNCTION
宏放在头文件中函数声明上方的行中。宏将支持 函数说明符 更改虚幻引擎解译和使用函数的方式。
UFUNCTION([specifier1=setting1, specifier2, ...], [meta(key1="value1", key2, ...)])
ReturnType FunctionName([Parameter1, Parameter2, ..., ParameterN1=DefaultValueN1, ParameterN2=DefaultValueN2]) [const];
可利用函数说明符将UFunction对蓝图可视化脚本图表公开,以便开发者从蓝图资源调用或扩展UFunction,而无需更改C++代码。在类的默认属性中,UFunction可绑定到委托,从而能够执行一些操作(例如将操作与用户输入相关联)。它们还可以充当网络回调,这意味着当某个变量受网络更新影响时,用户可以将其用于接收通知并运行自定义代码。用户甚至可创建自己的控制台命令(通常也称 debug、configuration 或 cheat code 命令),并能在开发版本中从游戏控制台调用这些命令,或将拥有自定义功能的按钮添加到关卡编辑器中的游戏对象。
函数说明符
声明函数时,可以为声明添加 函数说明符,以控制函数相对于引擎和编辑器的各个方面的行为方式。
函数说明符 |
效果 |
---|---|
|
如果在具有网络权限的机器上运行(服务器、专用服务器或单人游戏),此函数将仅从蓝图代码执行。 |
|
此函数可在蓝图或关卡蓝图图表中执行。 |
|
此函数为修饰性的,无法在专用服务器上运行。 |
|
此函数可在蓝图或关卡蓝图图表中实现。 |
|
此函数旨在被蓝图覆盖掉,但是也具有默认原生实现。用于声明名称与主函数相同的附加函数,但是末尾添加了`Implementation |
|
此函数不对拥有它的对象产生任何影响,可在蓝图或关卡蓝图图表中执行。 |
|
可通过细节(Details)面板`中的按钮在编辑器中的选定实例上调用此函数。 |
|
在蓝图编辑工具中显示时指定函数的类别。使用 | 运算符定义嵌套类别。 |
|
此函数仅在拥有在其上调用此函数的对象的客户端上执行。用于声明名称与主函数相同的附加函数,但是末尾添加了`Implementation |
|
|
|
此函数可从游戏内控制台执行。仅在特定类中声明时,Exec命令才有效。 |
|
此函数将在服务器上本地执行,也将复制到所有客户端上,无论该Actor的 |
|
此函数将通过网络复制,并且一定会到达,即使出现带宽或网络错误。仅在与`Client`或`Server`配合使用时才有效。 |
|
无法在子类中覆盖此函数。 |
|
此函数为RPC(远程过程调用)服务请求。这意味着 |
|
此函数为RPC服务响应。这意味着 |
|
此函数仅在服务器上执行。用于声明名称与主函数相同的附加函数,但是末尾添加了 |
|
此函数将通过网络复制,但是可能会因带宽限制或网络错误而失败。仅在与`Client`或`Server`配合使用时才有效。 |
|
用于声明名称与主函数相同的附加函数,但是末尾需要添加`_Validate`。此函数使用相同的参数,但是会返回`bool`,以指示是否应继续调用主函数。 |
元数据说明符
声明类、接口、结构体、列举、列举值、函数,或属性时,可添加 元数据说明符 来控制其与引擎和编辑器各方面的相处方式。每一种类型的数据结构或成员都有自己的元数据说明符列表。
函数元标签 |
效果 |
---|---|
|
以逗号分隔的参数列表将显示为高级引脚(需要UI扩展)。 |
|
用一个数字替代 |
|
说明 |
|
使用 |
|
如列出参数(由引用传递)的引脚未连接,其将拥有一个自动创建的默认项。这是蓝图的一个便利功能,经常在数组引脚上使用。 |
|
仅能由来自蓝图函数库的静态 |
|
此函数是一个内部实现细节,用于实现另一个函数或节点。其从未直接在蓝图图表中公开。 |
|
此函数只能在蓝图中的拥有对象上调用。其无法在另一个实例上调用。 |
|
用于拥有一个 |
|
说明 |
|
说明 |
|
列出的参数都会被视为通配符。此说明符需要 要声明自定义 |
|
用于 |
|
蓝图对此函数进行引用时将引起编译警告,告知用户函数已废弃。可使用 |
|
如果函数已废弃,尝试编译使用此函数的蓝图时,其将被添加到标准废弃警告。 |
|
被标记为 |
|
此节点在蓝图中的命名将被此处提供的值所取代,而非代码生成的命名。 |
|
用于 |
|
用于 |
|
隐藏用于指出函数调用所处对象的self引脚。self引脚在与调用蓝图的类兼容的 |
|
与 |
|
指定在搜索此函数时可使用的一套关键词,例如合适放置节点在蓝图图表中调用函数。 |
|
说明一个延迟操作。延迟操作拥有类型为 |
|
用于延迟 |
|
用于 |
|
用于 |
|
只在蓝图函数库中有效。此函数将被视为拥有类的整体 |
|
完整提示文本过长时使用的简短提示文本,例如父类选取器对话。 |
|
覆盖从代码注释自动生成的提示文本。 |
|
在Actor构造时调用此函数并非安全操作。 |
|
由 |
接口
创建和实现接口的引用
接口类有助于确保一组(可能)不相关的类实现一组通用函数。在某些游戏功能可能被大量复杂而不同的类共享的情况下,这非常有用。例如,某个游戏可能有这样一个系统,依靠该系统输入一个触发器体积可以激活陷阱、警告敌人或向玩家奖励点数。这可以通过针对陷阱、敌人和点数奖励器执行"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"。
#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)"的类将包含所有接口函数,且此类实际上将被您的其他类继承。
接口说明符
接口说明符 |
含义 |
---|---|
"BlueprintType" |
将该类公开为可用于蓝图中的变量的类型。 |
"DependsOn=(ClassName1, ClassName2, ...)" |
所有列出的类都将在该类之前编译。ClassName必须在同一个(或上一个)包中指定一个类。多个依赖性类可以使用以逗号分隔的单个"DependsOn"行来指定,也可以使用单个"DependsOn"行为每个类指定。当一个类使用在另一个类中声明的结构体或枚举时,这一点非常重要,因为编译器只知道它已经编译的类中的内容。 |
"MinimalAPI" |
仅导致该类的类型信息被导出以供其他模块使用。您可以向该类转换,但不能调用该类的函数(内联方法除外)。对于不需要其所有函数在其他模块中均可供访问的类,通过不导出这些类的所有内容,这可以缩短编译时间。 |
在C++中实现接口
若要在一个新的类中使用您的接口,只需从"前缀为I(I-prefixed)"的接口类继承(除了您正在使用的任何基于"UObject"的类)即可。
在C++中实现接口
若要在一个新的类中使用您的接口,只需从"前缀为I(I-prefixed)"的接口类继承(除了您正在使用的任何基于"UObject"的类)即可。
#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++函数。这些函数必须为虚拟的,以便在实现接口的类中覆盖它们。
可以在接口的头文件中声明一个不带 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
宏。还必须使用 BlueprintImplementableEvent
或 BlueprintNativeEvent
说明,而且函数不能为虚拟的。
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
说明符的函数。
BlueprintImplementableEvent
使用 BlueprintImplementableEvent
的函数不能在C++中被腹杆,但可以任何实现或继承接口的蓝图类中被覆盖。
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派生的类,则Acto
元数据说明符
声明UClasses、UFunctions、UProperties、UEnums和UInterfaces时使用的元数据关键词,说明其与虚幻引擎和关卡编辑器诸多方面的互动方式。
要添加元数据说明符到列举值,可将 UMETA
标签添加到值本身。如果存在用于分隔的逗号,则要添加到逗号之前,如下所示:
UENUM()
enum class EMyEnum : uint8
{
// Default Value Tooltip
DefaultValue = 0 UMETA(MetaTag1="Value1", MetaTag2, ..),
// ValueWithoutMetaSpecifiers Tooltip
ValueWithoutMetaSpecifiers,
// ValueWithMetaSpecifiers Tooltip
ValueWithMetaSpecifiers UMETA((MetaTag1="Value1", MetaTag2, ..),
// FinalValue Tooltip
FinalValue (MetaTag1="Value1", MetaTag2, ..)
};
类元数据说明符
|
如其存在,组件类可由蓝图生成。 |
|
只在蓝图函数库上有效。此说明符将把此类中的函数在动画蓝图中的非游戏线程上标记为可调用。 |
|
用于Actor和组件类。如果本地类无法tick,那么基于此Actor或组件的蓝图生成类则无法tick,即使 |
|
用于Actor和组件类。如果本地类无法tick,那么可以覆盖基于此Actor或组件的蓝图生成类的 |
|
用于行为树节点,说明类已废弃,编译时将显示一条警告。 |
|
如果类已废弃,尝试编译使用此类的蓝图时,其将被添加到标准废弃警告。 |
|
此节点在蓝图中的命名将被此处提供的值所取代,而非代码生成的命名。 |
|
不使用蓝图中的Generic Create Object节点来生成类的一个对象。此说明符只有在用于既非Actor又非ActorComponent的BluprintType类时才有意义。 |
|
在 Async Task 节点中公开此类的一个代理对象。 |
|
用于让一个类的首个子类忽略所有继承的 |
|
说明此类是否为创建蓝图的一个可接受基类,与 |
|
不允许被覆盖的蓝图事件的列表。 |
|
列出与类不兼容的接口。 |
|
由蓝图函数库类使用,用于限制列表中命名类的用法。 |
|
完整提示文本过长时使用的简短提示文本,例如父类选取器对话。 |
|
说明放置在此类拥有的图表中的蓝图节点必须显式其World情景引脚(即使其通常状态下为隐藏也同样如此),因为此类的对象无法被用作World情景。 |
|
说明类使用层级数据。用于实例化"细节"面板中的层级编辑功能。 |
|
覆盖从代码注释自动生成的提示文本。 |
对象
UCLASS 宏
UCLASS 宏为 UObject
提供了一个 UCLASS
引用,用于描述它在虚幻引擎中的类型。每个 UCLASS 都保留一个称作 类默认对象(Class Default Object) 的对象,简称CDO。CDO 本质上是一个默认"模板"对象,由类构建函数生成,之后就不再修改。 你可以为指定对象获取其 UCLASS 和 CDO,虽然它们通常都是只读类型。 使用 GetClass()
函数即可随时访问对象实例的 UCLASS。
属性和函数类型
UObjects 可拥有成员变量(称作属性)或任意类型的函数。然而,为便于虚幻引擎识别并操控这些变量或函数,它们必须以特殊的宏进行标记,并符合一定类型的标准。如需了解这些标准的细节,请查阅属性和UFunction参考页面。
UObject 创建
UObjects 不支持构造器参数。所有的C++ UObject都会在引擎启动的时候初始化,然后引擎会调用其默认构造器。如果没有默认的构造器,那么 UObject 将不会编译。
UObject 构造器应该轻量化,仅用于设置默认的数值和子对象,构造时不应该调用其它功能和函数。对于 Actor和Actor组件,初始化功能应该输入 BeginPlay()
方法。
UObject 应该仅在运行时使用 NewObject 构建,或者将 CreateDefaultSubobject 用于构造器。
方法 |
描述 |
---|---|
使用所有可用创建选项的可选参数创建一个新实例。提供极高的灵活性,包括带自动生成命名的简单使用案例。 |
|
|
创建一个组件或者子对象,可以提供创建子类和返回父类的方法。 |
UObjects 提供的功能
此系统的使用不为强制要求,甚至有时不适合使用,但却存在以下益处:
-
垃圾回收
-
引用更新
当PendingKill默认禁用时,开发者不需要担心引用更新,这一行可以在该UE版本中移除。
-
反射
-
序列化
-
默认属性变化自动更新
-
自动属性初始化
-
自动编辑器整合
-
运行时类型信息可用
-
网络复制
虚幻头文件工具
为利用 UObject 派生类型所提供的功能,需要在头文件上为这些类型执行一个预处理步骤,以核对需要的信息。该预处理步骤由 UnrealHeaderTool(简称 UHT)执行。UObject 派生的类型需要遵守特定的结构。
头文件格式
UObject 在源(.cpp)文件中的实现与其他 C++ 类相似,其在头(.h)文件中的定义必须遵守特定的基础结构,以便在虚幻引擎 4 中正常使用。使用编辑器的 New C++ Class 命令是设置格式正确头文件的最简单方法。UObject 派生类的基础头文件可能看起来与此相似,假定 UObject 派生物被称为 UMyObject,其创建时所在的项目被称为 MyProject:
#pragma once
#include 'Object.h'
#include 'MyObject.generated.h'
UCLASS()
class MYPROJECT_API UMyObject : public UObject
{
GENERATED_BODY()
};
虚幻引擎特定的部分如下:
#include "MyObject.generated.h"
UCLASS
宏使虚幻引擎能识别 UMyObject
。此宏支持大量参数类说明符,参数决定类功能的开或关
此行预计为此文件中最后一个 #include
指令。如此头文件需要了解其他类,可将它们在文件中的任意位置提前声明,或包括在 MyObject.generated.h 上。
UCLASS()
UCLASS
宏使虚幻引擎能识别 UMyObject
。此宏支持大量参数类说明符,参数决定类功能的开或关。
class MYPROJECT_API UMyObject : public UObject
如 MyProject 希望将 UMyObject 类公开到其他模块,则需要指定 MYPROJECT_API
。这对游戏项目将包括的模块或插件十分实用。这些模块和插件将故意使类公开,在多个项目间提供可携的自含式功能。
GENERATED_BODY()
更新对象
Ticking 代表虚幻引擎中对象的更新方式。所有Actors均可在每帧被 tick,便于您执行必要的更新计算或操作。
Actor 和 Actor组件在注册时会自动调用它们的 Tick 函数,然而,UObjects
不具有嵌入的更新能力。在必须的时候,可以使用 inherits 类说明符从 FTickableGameObject
继承即可添加此能力。 这样即可实现 Tick()
函数,引擎每帧都将调用此函数。
销毁对象
对象不被引用后,垃圾回收系统将自动进行对象销毁。这意味着没有任何 UPROPERTY
指针、引擎容器、TStrongObjectPtr
或类实例会拥有任何对它的强引用。
UObject实例创建
NewObject
NewObject()
是最简单的UObject工厂方法。它接受一个可选的外部对象和类,并用自动生成的名称创建一个新实例。
template< class T >
T* NewObject
(
UObject* Outer=(UObject*)GetTransientPackage(),
UClass* Class=T::StaticClass()
)
参数 |
说明 |
---|---|
|
可选。一个要设置为待创建对象的外部`UObject`。 |
|
可选。一个用于指定待创建对象类的`UClass`。 |
Return Value |
指向指定类的生成实例指针。 |
NewNamedObject
通过允许为新实例指定一个名称以及对象标记和一个要指定为参数的模板对象,NewNamedObject()
在 NewObject()
上展开。
template< class TClass >
TClass* NewNamedObject
(
UObject* Outer,
FName Name,
EObjectFlags Flags = RF_NoFlags,
UObject const* Template=NULL
)
参数 |
说明 |
---|---|
|
一个要设置为待创建对象的外部的`UObject`。 |
|
一个要设置为新对象的 |
|
可选。描述新对象的 `FObjectFlags`枚举值。 |
|
可选。创建新对象时用作模板的 |
Return Value |
指向指定类的生成实例指针。 |
ConstructObject
为了获得完全的灵活性,可以使用`ConstructObject()函数创建`UObjects`的新实例。此函数调用`StaticConstructObject()
,它分配对象,执行`ClassConstructor`,并执行任何初始化,如加载配置属性,加载本地化属性和实例化组件。
template< class T >
T* ConstructObject
(
UClass* Class,
UObject* Outer = (UObject*)GetTransientPackage(),
FName Name=NAME_None,
EObjectFlags SetFlags=RF_NoFlags,
UObject const* Template=NULL,
bool bCopyTransientsFromClassDefaults=false,
struct FObjectInstancingGraph* InstanceGraph=NULL
)
参数 |
说明 |
---|---|
|
一个用于指定待创建对象的类的`UClass`。 |
|
可选。一个要设置为待创建对象的外部`UObject`。 |
|
可选。一个要设置为新对象的`名称(Name) |
|
可选。描述新对象的`EObjectFlags`枚举值。 |
|
可选。创建新对象时用作模板的`UObject`。 |
|
可选。一个`布尔值 |
|
可选。`FObjectInstancingGraph`结构体,包含实例化对象和组件到其模板的映射。用于实例化新对象所拥有的组件。 |
Return Value |
指向指定类的生成实例指针。 |
属性
属性声明
属性使用标准的C++变量语法声明,前面用UPROPERTY宏来定义属性元数据和变量说明符。
UPROPERTY([specifier, specifier, ...], [meta(key=value, key=value, ...)])
Type VariableName;
核心数据类型
整数
整数数据类型转换是"int"或"uint"后跟位大小。
变量类型 |
说明 |
---|---|
uint8 |
8位无符号 |
uint16 |
16位无符号 |
uint32 |
32位无符号 |
uint64 |
64位无符号 |
int8 |
8位有符号 |
int16 |
16位有符号 |
int32 |
32位有符号 |
int64 |
64位有符号 |
作为位掩码
整数属性现在可以位掩码形式公开给编辑器。要将整数属性标记为位掩码,只需在meta分段中添加"bitmask"即可,如下所示:
/*~ BasicBits appears as a list of generic flags in the editor, instead of an integer field. */
UPROPERTY(EditAnywhere, Meta = (Bitmask))
int32 BasicBits;
文章评论