
目录一Adding Classes二Class HeadersClass DeclarationClass SpecifiersMetadata Specifiers三Class ImplementationClass Constructor引擎中每个游戏类都由一个头文件.h和一个源文件.cpp构成头文件包含类和类成员如变量和函数的声明而源文件是类功能的实现类通过首字母或前缀来标准化的命名一Adding Classes主菜单Tools New C Class...是一种快速简便的方法将本机C代码类添加到项目中以便根据需要扩展功能这会将纯内容项目转换为代码项目确保安装了兼容版本的Visual Studio二Class Headers引擎中的类通常拥有单独且唯一的头文件通常这些文件的命名与其中定义的类相匹配减去A或U前缀并使用.h文件扩展名如AActor类的类头文件命名为Actor.h头文件使用标准 C 语法并结合专门的宏以简化类、变量和函数的声明过程// 在每个头文件都包含自动生成的头文件 #include ClassName.generated.hClass Declaration类声明定义类的名称、其继承的类以及继承的函数和变量通过类说明符和元数据类声明还定义了引擎和编辑器的特定行为UCLASS([specifier, specifier, ...], [meta(key value, key value, ...)]) class ClassName : public ParentName { GENERATED_BODY() // 必须被放置在类体的最前方 }Class Specifiers在类声明中添加类说明符以控制类在引擎和编辑器的各个方面如何表现Class SpecifierEffectAbstract声明为抽象基类不可向关卡中添加此类的Actor如ATriggerBase基类是抽象类而ATriggerBox子类不是抽象类可以放置在关卡Blueprintable将此类公开为用于创建蓝图的可接受基类默认为NotBlueprintable子类会继承NotBlueprintable指定此类不是可用于创建蓝图的可接受基类此为默认说明符子类会继承BlueprintType将此类公开为可用于蓝图变量的类型Const此类中的所有属性和函数都是const并且导出为const子类会继承ConversionRoot根转换将子类限制为仅可沿层级向上转换为第一个根类的子类CustomConstructor阻止构造函数声明自动生成DefaultToInstanced此类的所有实例都被认为是实例化的实例化的类组件将在构造时被复制子类会继承EditInlineNew可从编辑器Property窗口创建此类的对象而非从现有资源引用默认仅可通过Property窗口指定对现有对象的引用此说明符会传播到所有子类子类可通过NotEditInlineNew说明符覆盖它Intrinsic此类直接在C中声明无Unreal Header Tool生成的样板请勿在新类上使用此说明符MinimalAPI仅导出类的类型信息供其他模块使用该类可被类型转换但无法调用该类的函数内联方法除外对于不需要在其他模块中访问所有函数的类通过不导出所有内容可以缩短编译时间NoExport此类的声明不应包含在自动生成的C头文件中必须在单独的头文件中手动定义该C类声明仅对本地类有效请勿对新类使用此说明符Transient属于此类别的对象将永远不会保存到磁盘与非持久性的本地类别如玩家或窗口结合使用时非常有用此说明符会传递给子类但可以被非瞬态说明符覆盖NonTransient使继承自基类的Transient说明符无效Placeable可在编辑器中创建此类且可将此类放置到关卡、UI场景或蓝图取决于类类型中此标志会传播到所有子类子类可使用NotPlaceable说明符覆盖此标志NotPlaceable使继承自基类的Placeable说明符无效不可以在编辑器中将此类的对象放置到关卡、UI场景或蓝图中PerObjectConfig此类别的配置信息将按对象存储其中每个对象在.ini文件中都有一个以对象名称命名的部分格式为[ObjectName ClassName]此说明符会传递给子类WithinOuterClassName此类的对象无法在OuterClassName对象的实例之外存在要创建此类的对象需要提供OuterClassName的一个实例作为其Outer对象AdvancedClassDisplay强制类的所有属性仅显示在细节面板的Advanced部分ClassGroupGroupName在编辑器的Actor浏览器中启用Group View时Actor Browser应在指定的GroupName中包含此类及其所有子类ConfigConfigName此类可在配置文件.ini中存储数据如存在使用config或globalconfig说明符的类属性将使这些属性存储在指定的配置文件中会传播到所有子类并且无法使其无效但是子类可通过重新声明config说明符并提供不同的ConfigName来更改配置文件常见的ConfigName值是Engine、Editor、Input和GameDependsOn(ClassName1, ClassName2, ...)所列的类将先于此类被编译提供的类名必须指明是同一或之前包中的类可使用单个DependsOn行以逗号分隔来标识多个依赖类或通过为每个类使用单独的DependsOn行来指定多个依赖类当某个类使用在另一个类中声明的结构体或枚举时这非常重要因为编译器只知道它已经编译过的类中的内容Deprecated此类已弃用序列化时将不保存此类的对象子类会继承AutoCollapseCategories(Category1, Category2, ...)使父类上的AutoExpandCategories说明符列出类别的效果无效AutoExpandCategories(Category1, Category2, ...)指定应自动在编辑器属性窗口中展开的一个或多个类别要自动展开未使用类别变量使用类名称DontAutoCollapseCategories(Category, Category, ...)使列出类别的继承自父类的AutoCollapseCategories说明符无效CollapseCategories此类的属性不应划分到编辑器属性窗口的类别中会传播到子类可由DontCollapseCategories说明符覆盖DontCollapseCategories使继承自基类的CollapseCatogories说明符无效ShowCategories(Category1, Category2, ...)使继承自基类的HideCategories说明符无效HideCategories(Category1, Category2, ...)列出对用户完全隐藏的类别此说明符会传播到子类要隐藏未使用类别声明的属性使用声明变量的类的名称ShowFunctions(Category1, Category2, ...)在属性查看器中显示列出的类别中的所有函数HideFunctions(Category1, Category2, ...)让指定分类中的所有函数都对用户完全隐藏ShowFunctionsFunctionName在属性查看器中显示指定的函数HideFunctionsFunctionName将提到的函数对用户完全隐藏HideDropdown阻止此类在属性窗口组合框中显示Metadata Specifiers在声明类、接口、结构体、枚举/枚举值、函数或属性时可以添加元数据说明符来控制其与引擎和编辑器各个方面的交互方式每种数据结构或成员类型都有其自己的元数据说明符列表元数据仅存在于编辑器中请勿编写访问元数据的游戏逻辑Class Meta TagEffectBlueprintSpawnableComponent如其存在组件类可由蓝图生成BlueprintThreadSafe只在蓝图函数库上有效将把此类中的函数在动画蓝图中的非游戏线程上标记为可调用ChildCannotTick用于Actor和组件类如本地类无法tick那么基于此Actor或组件的蓝图生成类则无法tick即使bCanBlueprintsTickByDefault为true也同样如此ChildCanTick用于Actor和组件类如本地类无法tick那么可以覆盖基于此Actor或组件的蓝图生成类的bCanEverTick标签即使bCanBlueprintsTickByDefault为false也同样如此DeprecatedNode用于行为树节点说明类已废弃编译时将显示一条警告DeprecationMessageMessage Text如类已废弃尝试编译使用此类的蓝图时会添加到标准废弃警告DisplayNameBlueprint Node Name此节点在蓝图中的命名将被此处提供的值所取代而非代码生成的命名DontUseGenericSpawnObject不使用蓝图中的通用Create Object节点来生成类的一个对象此说明符只有在用于既非Actor又非ActorComponent的BluprintType类时才有意义ExposedAsyncProxy在Async Task节点中公开此类的一个代理对象IgnoreCategoryKeywordsInSubclasses用于让一个类的首个子类忽略所有继承的ShowCategories和HideCategories说明符IsBlueprintBasetrue/false说明此类是否为创建蓝图的一个可接受基类与UCLASS说明符Blueprintable或NotBlueprintable相似KismetHideOverridesEvent1, Event2, ..不允许被覆盖的蓝图事件的列表ProhibitedInterfacesInterface1, Interface2, ..列出与类不兼容的接口RestrictedToClassesClass1, Class2, ..由蓝图函数库类使用用于限制列表中命名类的用法ToolTipHand-written tooltip覆盖从代码注释自动生成的提示文本ShortToolTipShort tooltip完整提示文本过长时使用的简短提示文本如父类选取器对话ShowWorldContextPin说明放置在此类拥有的图表中的蓝图节点必须显式其World情景引脚即使其通常状态下为隐藏也同样如此因为此类的对象无法被用作World情景UsesHierarchy表示类使用层级数据用于实例化细节面板中的层级编辑功能ScriptNameDisplayName在将此类、属性或函数导出到脚本语言时使用的名称可以包含已弃用的名称作为额外的以分号分隔的条目三Class Implementation所有类必须使用GENERATED_BODY宏才能正确实现这是在定义类及其所有变量和函数的类头.h文件中完成的最佳方法是使类源和头文件的命名与实现的类相匹配减去A或U前缀如AActor类的源文件命名为Actor.cpp其头文件命名为Actor.h对编辑器中Add C Class而言是自动进行源文件.cpp必须包含 C 类声明的头文件.h通常为自动生成但也可手动生成如有必要如AActor类的 C 声明在EngineClasses.h头文件中自动生成Actor.cpp文件必须包括EngineClasses.h文件或包含它的另一个文件Class ConstructorUObjects使用Constructors设置属性和其他变量的默认值并执行其他必要的初值设定类构造函数通常放置在类实现文件中如AActor::AActor构造函数位于Actor.cpp中注部分构造函数可能以每个模块为基础放置在一个特殊的constructors文件中也可以将构造函数内联放置在类头文件中然而如果构造函数在类头文件中UClass 必须结合CustomConstructor说明符进行声明因为这阻止了自动代码生成器在标头中创建构造函数声明Constructor Format// UObject 构建函数最基本的形式 UMyObject::UMyObject() { // 在此处初始化 Class Default Object 属性 }// 另一个辅助构造函数支持一个特殊的属性调整结构 UMyObject::UMyObject(const FObjectInitializer ObjectInitializer) : Super(ObjectInitializer) { // Initialize CDO properties here. }尽管上述两个构造函数实际上都没有执行任何初始化操作但引擎已经将所有字段初始化为零、NULL或其默认构造函数所实现的任何值任何在构造函数中的初始化代码都将应用于CDO也会被复制到正确创建的对象的任何新实例中就像使用CreateNewObject或SpawnActor一样传递给构造函数的FObjectInitializer参数尽管被标记为const但可以通过内置的可变函数进行配置以覆盖属性和子对象正在创建的UObject将受到这些更改的影响并且这可用于更改已注册属性或组件的值AUDKEmitterPool::AUDKEmitterPool(const FObjectInitializer ObjectInitializer) : Super(ObjectInitializer.DoNotCreateDefaultSubobject(TEXT(SomeComponent)).DoNotCreateDefaultSubobject(TEXT(SomeOtherComponent))) { // Initialize CDO properties here. }在上例中超类将在其构建函数中创建名为SomeComponent和SomeOtherComponent的子对象但由于 FObjectInitializer 的原因该操作将不会执行在下例中SomeProperty在 CDO 中将默认为 26因此在 AUTDemoHUD 的每个新实例中均为如此AUTDemoHUD::AUTDemoHUD() { // 在此处初始化 CDO 属性 SomeProperty 26; }Constructor Statics and Helpers为更复杂的数据类型尤其是类引用、名称和资源引用设置值时需在构造函数中定义并实例化一个 ConstructorStatics 结构体来保存所需的各种属性值该结构体仅在构造函数首次运行时创建在后续运行中它只需复制一个指针因此速度极快在创建 ConstructorStatics 结构体时会将值分配给该结构体的成员以便在构造函数后续将值分配给实际属性时进行访问ContructorHelpers是在ObjectBase.h中定义的一个特殊命名空间其中包含用于执行特定于构造函数的常见操作的辅助模板如存在用于查找资源或类引用以及创建和查找组件的辅助模板Asset References理想情况下类中不应存在资源引用硬编码的资源引用易出错更推荐使用蓝图来配置资源属性不希望每次构造对象时都搜索资源通过一个静态结构体确保只进行一次资源搜索ConstructorHelpers::FObjectFinder通过 StaticLoadObject 函数查找指定 UObject 的引用通常用于引用存储在内容包中的资源如未找到对象则会报告失败ATimelineTestActor::ATimelineTestActor() { // Structure to hold one-time initialization struct FConstructorStatics { ConstructorHelpers::FObjectFinderUStaticMesh Object0; FConstructorStatics() : Object0(TEXT(StaticMesh/Game/UT3/Pickups/Pickups/Health_Large/Mesh/S_Pickups_Base_Health_Large.S_Pickups_Base_Health_Large)) { } }; static FConstructorStatics ConstructorStatics; // Property initialization StaticMesh ConstructorStatics.Object0.Object; }Class ReferencesConstructorHelpers::FClassFinder为特定的UClass寻找引用如类未找到则报告失败APylon::APylon(const class FObjectInitializer ObjectInitializer) :Super(ObjectInitializer) { // 进行一次性初始化的结构 static FClassFinderUNavigationMeshBase ClassFinder(TEXT(classEngine.NavigationMeshBase)); if (ClassFinder.Succeeded()) NavMeshClass ClassFinder.Class; else NavMeshClass nullptr; }在许多情况下可只使用USomeClass::StaticClass()绕开复杂的全部 ClassFinder对跨模块的引用而言使用 ClassFinder 法较好NavMeshClass UNavigationMeshBase::StaticClass();Components and Sub-Objects在构造函数中也可创建组件子对象并将其附加到角色的层次结构中当生成一个角色时其组件将从CDO中克隆为了确保组件始终被创建、销毁并正确地进行垃圾回收应在所属类的UPROPERTY中存储一个指向构造函数中创建的每个组件的指针UCLASS() class AWindPointSource : public AActor { GENERATED_BODY() public: UPROPERTY() UWindPointSourceComponent* WindPointSource; UPROPERTY() UDrawSphereComponent* DisplaySphere; }; AWindPointSource::AWindPointSource() { // Create a new component and give it a name. WindPointSource CreateDefaultSubobjectUWindPointSourceComponent(TEXT(WindPointSourceComponent0)); // Set our new component as the RootComponent of this actor, or attach it to the root if one already exists. if (RootComponent nullptr) RootComponent WindPointSource; else WindPointSource-AttachTo(RootComponent); // Create a second component. This will be attached to the component we just created. DisplaySphere CreateDefaultSubobjectUDrawSphereComponent(TEXT(DrawSphereComponent0)); DisplaySphere-AttachTo(RootComponent); // Set some properties on the new component. DisplaySphere-ShapeColor.R 173; DisplaySphere-ShapeColor.G 239; DisplaySphere-ShapeColor.B 231; DisplaySphere-ShapeColor.A 255; DisplaySphere-AlwaysLoadOnClient false; DisplaySphere-AlwaysLoadOnServer false; DisplaySphere-bAbsoluteScale true; }