目录
一,UObject Instance Creation
NewObject
NewNamedObject
ConstructObject
Object Flags
二,Unreal Object Handling
Automatic Property Initialization
Automatic Updating of References
Serialization
Updating of Property Values
Editor Integration
Run-Time Type Information and Casting
Garbage Collection
Network Replication
一,UObject Instance Creation
创建对象新实例的方法;
NewObject
NewObject()
是最简单的UObject工厂方法;它接受一个可选的外部对象和类,并用自动生成的名称创建一个新实例;
template< class T >
T* NewObject
(UObject* Outer = (UObject*)GetTransientPackage(),UClass* Class = T::StaticClass()
)
- Outer,可选,一个待创建对象的外部
UObject
; - Class,可选,一个待创建对象类的
UClass
; - 返回值,指向生成实例(指定类)指针;
NewNamedObject
NewNamedObject()
是在 NewObject()
上扩展,通过为新实例指定一个名称、对象标记、一个要指定为参数的模板对象;
template< class TClass >
TClass* NewNamedObject
(UObject* Outer,FName Name,EObjectFlags Flags = RF_NoFlags,UObject const* Template = NULL
)
- Outer,一个待创建对象的外部
UObject
; - Name,一个为新对象的
名称
的FName
; - Flags,可选,描述新对象的
FObjectFlags
枚举值; - Template,可选,创建新对象时用作模板的
UObject
; - 返回值,指向生成实例(指定类)指针;
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
)
- Class,一个待创建对象类的
UClass
; - Outer,可选,一个待创建对象的外部
UObject
; - Name,可选,一个为新对象的
名称
的FName
; - SetFlags,可选,描述新对象的
FObjectFlags
枚举值; - Template,可选,创建新对象时用作模板的
UObject
; - bCopyTransientsFromClassDefaults,可选,
- FObjectInstancingGraph,可选,一个
布尔值
,决定是否从类默认对象(而不是传入的原型指针)复制瞬态属性;如果true
,使用类默认对象的瞬态; - 返回值,指向生成实例(指定类)指针;
Object Flags
EObjectFlags
枚举用于快速而简洁地描述对象;有各种的标志来描述对象的类型、垃圾收集如何处理它、对象在其生命周期中所处的阶段等等;还有特殊的全掩码或无掩码和预定义的标记组;
Flag | Value | Description |
RF_Public | 0x00000001 | 对象在包含它的包外部是可见的; |
RF_Standalone | 0x00000002 | 即使没有被任何东西引用,对象也会被保留以供编辑; |
RF_Native | 0x00000004 | 对象是本地对象,仅用于 UClass 对象; |
RF_Transactional | 0x00000008 | 对象是事务对象; |
RF_ClassDefaultObject | 0x00000010 | 对象是其类的默认对象,即该类的新实例在创建时使用的默认模板; |
RF_ArchetypeObject | 0x00000020 | 对象是另一个对象的模板。它被视为一个类默认对象; |
RF_Transient | 0x00000040 | 对象不保存到磁盘; |
Flag | Value | Description |
RF_RootSet | 0x00000080 | 即使对象没有被任何东西引用,也不被垃圾回收; |
RF_IsLazyReferenced | 0x00000100 | 对象由一个延迟指针引用,删除时需要额外的清理; |
RF_Unreachable | 0x00000400 | 对象图表上不能访问该对象; |
RF_TagGarbageTemp | 0x00000400 | 对象被标记为供使用垃圾回收的各种实用程序所使用;此标记不由垃圾回收器本身解释; |
Flag | Value | Description |
RF_NeedLoad | 0x00000800 | 对象需要加载; |
RF_AsyncLoading | 0x00001000 | 对象是异步加载的; |
RF_NeedPostLoad | 0x00002000 | 对象需要后加载; |
RF_NeedPostLoadSubobjects | 0x00004000 | 对象仍然需要实例化子对象并修复序列化的组件引用; |
RF_PendingKill | 0x00008000 | 对象正在等待销毁;基于游戏目的将对象标记为无效,但仍然是有效的对象; |
RF_BeginDestroyed | 0x00010000 | 对象已经调用了 BeginDestroy() ; |
RF_FinishDestroyed | 0x00020000 | 对象已经调用了 FinishDestroy() ; |
Flag | Value | Description |
RF_AllFlags | 0x0003ffff | 对象具有所有标记,主要用于错误检查; |
RF_NoFlags | 0x00000000 | 对象不具有标记,用于避免类型转换; |
Flag | Value | Description |
RF_Load | RF_Public | RF_Standalone | RF_Native | RF_Transactional | RF_ClassDefaultObject | RF_ArchetypeObject | 从虚幻文件加载的标记; |
RF_PropagateToSubobjects | RF_Public | RF_ArchetypeObject | RF_Transactional | 子对象从其超对象继承的标记; |
二,Unreal Object Handling
使用适当的宏标记类、属性和函数可以将它们转变为UClasses
、UProperties
和UFunctions
;这让虚幻引擎能够访问它们,从而允许实现一些后台处理功能;
Automatic Property Initialization
在调用构造函数之前,UObject
在初始化时自动归零;这针对整个类发生,UProperties
和类似的原生成员;成员随后可以使用类构造函数中的自定义值进行初始化;
Automatic Updating of References
AActor
或UActorComponent
被销毁或从运行中删除时,对反射系统可见的对它的所有引用(UProperty
指针和引擎容器类中存储的指针,如TArray
)都将自动清空;这样的好处是防止悬挂指针持久存在并导致后续问题,但也意味着如果其他某段代码将AActor
和UActorComponent
指针销毁,这些指针也会变为空;最终的好处是空检查更可靠,因为会检测标准情况空指针和非空指针指向删除内存的情况;
必须理解的是,这种功能仅适用于标记了UPROPERTY
或存储在虚幻引擎容器类中的UActorComponent
或AActor
引用;存储在原始指针中的Object引用对于虚幻引擎将为未知,并且不会自动清空,也不会妨碍垃圾回收;注意,这不意味着所有UObject*
变量都必须是UProperties
;如需要的Object指针不是UProperty
,请考虑使用TWeakObjectPtr
;这是"弱"指针,意味着不会妨碍垃圾回收,但可以查询有效性,然后再接受访问,并且它所指向的Object要被销毁时,它将被设置为空;
另一种被引用UObject UProperty自动清空的情况是对编辑器中的资源使用"强制删除(Force Delete)";因此,作用于属于资源的UObject的所有代码都必须处理这些变为空的指针;
Serialization
当UObject
被序列化时,所有UProperty
值都将被自动写入或读取,除非显式标记为"瞬时"或无法从后构造函数默认值进行更改;如,可以在关卡中放入AEnemy
实例,将其"Health"设置为500,保存并成功地重新加载,而不必在UClass
定义之外编写一行代码;
当添加或删除UProperties时,系统会无缝处理加载预先存在的内容;新属性从新的CDO复制默认值;删除的属性将会被静默忽略;
如需要自定义行为,则可以覆盖UObject::Serialize
函数;这对于检测数据错误,检查版本号或执行自动转换或更新(如果数据格式有所更改)十分有用;
Updating of Property Values
当UClass
的 类默认对象(CDO)更改,引擎将尝试在加载类的所有实例时对这些实例应用这些更改;对于给定Object实例,如更新的变量值与旧CDO中的值相匹配,则将更新为它在新CDO中保存的值;如变量包含任何其他值,系统会假设这个值是故意设置的,这些更改将会被保留;
如,假设在一个关卡中放置了多个 AEnemy
Object并保存,然后将 AEnemy
构造函数中的默认Health值设置为100;再假设将Enemy_3的Health值设置为500,因为它们特别难对付;现在,假设改变主意,将Health的默认值增加到150;下次加载关卡时,虚幻意识到更改了CDO,并将使用旧默认Health值(100)的所有AEnemy
实例更新为使用Health值150。Enemy_3的Health将保持在500,因为它不使用旧的默认值;
Editor Integration
编辑器理解UObject
和UProperties
,编辑器可以自动公开这些值以供编辑,而不必编写特殊代码;可以选择在蓝图视觉脚本系统中融入集成,也有许多选项可以控制变量和函数的可访问性和公开;
Run-Time Type Information and Casting
由于UObject
是虚幻引擎反射系统的一部分,它们始终知道它们是哪些UClass
,并可以在运行时做出有关类型的决定和类型转换;
在原生代码中,每个UObject
类都将自定义Super
类型定义设置为其父类,从而可以轻松控制覆盖行为;
class AEnemy : public ACharacter
{virtual void Speak(){Say("Time to fight!");}
};class AMegaBoss : public AEnemy
{virtual void Speak(){Say("Powering up! ");Super::Speak();}
};
//调用Speak将会让MegaBoss说"Powering up!Time to fight!"
此外,可以使用模板化Cast函数或者查询(如Object是使用IsA
的特定类)安全地将Object从基类转换为更派生类;
class ALegendaryWeapon : public AWeapon
{void SlayMegaBoss(){TArray<AEnemy> EnemyList = GetEnemyListFromSomewhere();// The legendary weapon is only effective against the MegaBossfor (AEnemy Enemy : EnemyList){AMegaBoss* MegaBoss = Cast<AMegaBoss>(Enemy);if (MegaBoss){Incinerate(MegaBoss);}}}
};
使用了Cast
来尝试将AEnemy
转换为AMegaBoss
,如所提及Object实际上不是AMegaBoss
(或者其子类),则Cast会返回空指针;在以上代码中,Incinerate
将仅对MegaBoss调用;
Garbage Collection
虚幻实现垃圾回收机制,不再被引用或已被显式标记为销毁的UObject
将定期清理;引擎构建一个引用图表以确定哪些UObject
仍在使用,哪些是孤立的;在该图表根部是一组指定为"root set"的UObject
;任何UObject
都可以添加到root set;当进行垃圾回收时,引擎将从root set开始,搜索已知UObject
引用树来跟踪所有引用的UObject
;任何未被引用的UObject
(意味着未在树搜索中找到这些对象)将被假设为不再需要,因此被删除;
一个实际的影响是,通常需要保持对希望保持活跃的任何Object的UPROPERTY
引用,或将指向它的指针存储在TArray
或其他引擎容器类中;Actor及其组件通常属于例外情况,因为Actor通常被链接回到根集的Object引用(如它们所属的关卡),而Actor的组件被Actor自身引用;Actor可以显式标记为销毁,方法是调用它们的Destroy
函数,这是从进行中游戏移除Actor的标准方法;组件可以使用DestroyComponent
函数显式销毁,但它们通常在拥有它们的Actor从游戏中移除时被销毁;
虚幻引擎中的垃圾回收速度快,效率高,内置大量的优化功能,能够尽量降低开销,如多线程可访问性分析可以标识孤立Object,优化的unhashing代码能够尽快从容器中移除Actor;还有一些其他功能以调节,以更精准地控制如何以及何时执行垃圾回收,大部分都可以在 项目设置(Project Settings) 中的 引擎 - 垃圾回收(Engine - Garbage Collection) 下找到;
Setting(s) | Feature Description |
Create Garbage Collector UObject Clusters | 可在项目设置中打开或关闭(默认打开);如打开,相关Object将被分组到一起归入垃圾回收集群,这样只需要检查集群自身即可,而不必检查每个Object;这意味着可以更快速地执行可访问性,因为整个集群将被视为一个对象,但也意味着该集群中的单个项目将被unhashed,并准备在同一帧中删除,如集群足够大,这样可能会导致卡顿;一般而言,集群创建会提高垃圾回收性能,缩短可访问性分析耗费的时间; |
Merge GC Clusters | 可启用集群合并,这样当一个集群的对象引用另一个集群的对象时,让集群合并起来;注意,清空导致合并的引用不会让新合并的集群瓦解或拆散;Create Garbage Collector UObject Clusters 也必须打开,该功能才能工作;这会使垃圾回收器unhashing和销毁对象的频率降低,但一次unhashed和销毁的对象数量会增加;此外,有些情况下不会对合并集群进行垃圾回收,因为对该集群中任何对象的任何引用都会阻止对整个集群进行垃圾回收; |
Actor Clustering Enabled | 通过在 Project Settings 中打开这个选项,并将bCanBeInCluster 变量设置为true ,或覆盖代码中的CanBeInCluster 函数以使其返回true ,可以将Actor放入集群中;默认,Actor和组件会将这个选项关闭,但静态网格体Actor和反射捕获组件除外;该功能可用于将应该一次性全部销毁的Actor分组在一起,通常是关卡中放置的不能被销毁的静态网格体,除非卸载包含这些网格体的子关卡; |
Blueprint Clustering Enabled | 蓝图的UBlueprintGeneratedClass 和相关数据,如共享UPROPERTY和UFUNCTION数据,可以通过打开该设置来建立集群;必须要认识到的是,该集群引用蓝图生成的类自身,而不是蓝图的单个实例; |
Time Between Purging Pending Kill Objects | 垃圾回收活动的频率可以在项目设置中调整;该高级控制对于防止卡顿尤其有用;通过缩短回收间隔,可以减少将在下一次可访问性分析阶段发现的无法访问的对象的可能数量,并避免同时清除大量Actor时可能会发生的卡顿; |
Network Replication
UObject
系统包含一组可靠的功能,能够促进网络通信和多人游戏;
UProperties
可以标记为告诉引擎
在网络游戏期间复制数据;常见模型是一个变量在服务器上发生更改,引擎检测到这个更改,并将其可靠地发送到所有客户端;当变量通过复制发生更改时,客户端可以选择性接收回调函数;
UFunctions
也可以标记为
在远程机器上执行;如,"server"函数在客户端上调用时,将会在服务器上执行这个函数以获取服务器版本的Actor;而另一方面,"client"函数可以从服务器调用,并在拥有这个函数的客户端版本的对应Actor上运行;