UE4入门学习4:C++编程介绍
来源:互联网 发布:Java game simulation 编辑:程序博客网 时间:2024/05/10 22:35
UE4直接使用C++作为逻辑层语言,这样引擎层与逻辑层语言统一,不需要胶水代码去转发,消除了逻辑层和引擎层的交互成本。为了便于开发,UE4对C++做了一些包装,比如反射和垃圾回收,大大减轻C++开发的难度。本文结合UE4官方C++编程指南文档,对C++相关特性做一些描述和总结。
反射
C++本来是不支持反射的,只有一个基本的RTTI(运行时类型信息)特性,仅能在运行时获取对象的类型信息,无法得到成员变量和函数列表信息。如果我们要对成员变量进行序列化(存档/读档),需要自己写很多辅助的读取和写入方法,非常麻烦。
UE4在C++编译开始前,使用工具UnrealHeaderTool
,对C++代码进行预处理,收集出类型和成员等信息,并自动生成相关序列化代码。然后再调用真正的C++编译器,将自动生成的代码与原始代码一并进行编译,生成最终的可执行文件。这个过程类似于Qt的qmake预处理机制。
拿出我们之前工程的代码来分析:
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/Actor.h"#include "MyActor.generated.h"UCLASS()class HELLOUE4_API AMyActor : public AActor{ GENERATED_BODY()public: // 默认构造函数,初始化一些成员属性。 AMyActor();protected: // 游戏开始或者被创建出来后调用。 virtual void BeginPlay() override;public: // 每帧都会被调用 virtual void Tick(float DeltaTime) override; // 这个变量会出现在编辑器编辑界面。 UPROPERTY(EditAnywhere) int32 MyID;private: // 这是个内部变量。不会出现在编辑器界面。 float RunningTime;};
这个代码文件包含了一些特殊的头文件和宏,下面逐一介绍:
以下是MyActor.generated.h
中的部分代码:
#define HelloUE4_Source_HelloUE4_MyActor_h_9_INCLASS_NO_PURE_DECLS \ private: \ static void StaticRegisterNativesAMyActor(); \ friend HELLOUE4_API class UClass* Z_Construct_UClass_AMyActor(); \ public: \ DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), 0, TEXT("/Script/HelloUE4"), NO_API) \ DECLARE_SERIALIZER(AMyActor) \ /** Indicates whether the class is compiled into the engine */ \ enum {IsIntrinsic=COMPILED_IN_INTRINSIC};
实际上,GENERATED_BODY
这个宏最终展开后就对应了宏HelloUE4_Source_HelloUE4_MyActor_h_9_INCLASS_NO_PURE_DECLS
,也就是说自动生成的代码会在C++编译的时候注入到了类AMyActor
中。
注意,如果声明变量或类型不加上前缀,是不会生成类型信息的。下面是一些基本的类型标记:
- UCLASS() - 告诉UE4生成类的反射数据。类必须派生自 UObject。
- USTRUCT() - 告诉UE4生成结构体的反射数据。
- UENUM() - 告诉UE4生成枚举的反射数据。
- GENERATED_BODY() - UE4 使用它替代为类型生成的所有必需样板文件代码。
- UPROPERTY() - 使 UCLASS 或 USTRUCT 的成员变量可用作 UPROPERTY。UPROPERTY 用途广泛。它允许变量被复制、被序列化,并可从蓝图中进行访问。垃圾回收器还使用它们来追踪对 UObject 的引用数。
- UFUNCTION() - 使 UCLASS 或 USTRUCT 的类方法可用作 UFUNCTION。UFUNCTION 允许类方法从蓝图中被调用,并在其他资源中用作 RPC。
序列化
有了反射功能之后,成员变量的序列化也就更方便了。UE4收集了每个类成员的类型信息,这样存档和读档时,根据名称和类型就可以自动完成了,整个过程不需要人工干预。
需要序列化的成员变量,需要在变量声明的时候在前面加上UPROPERTY()
宏,宏参数有很多,分别表示变量的详细属性,下面列举一些常用的:
与UPROPERTY
对应的还有一个用于修饰函数的宏UFUNCTION
,该宏常用于描述如何从蓝图中访问C++的函数。
热重载
在编辑器模式下,UE4将工程代码编译成动态链接库,这样编辑器可以动态的加载和卸载某个动态链接库。UE4为工程自动生成一个cpp文件(本工程为HelloUE4.generated.cpp
),cpp文件包含了当前工程中所有需要反射的类信息,以及类成员列表和每个成员的类型信息。在动态链接库被编辑器加载的时候,自动将类信息注册到编辑器中。反之,卸载的时候,这样类信息也会被反注册。
在开发的过程中,当我们编译完成工程的时候,UE4编辑器会自动检测动态链接库的变化,然后自动热重载这些动态链接库中的类信息。
垃圾回收
有了反射机制,UE4也能够知道哪些类型是指针类型,以及哪些变量需要被垃圾收集系统管理。被垃圾收集系统管理的对象,不需要手动调用delete,只需要正确的维持变量的引用即可。我没有看过UE4垃圾收集系统实现源码,姑且将UE4的垃圾收集系统看成是一个使用了“标记-清扫”算法的一个沙盒,当不需要使用某个指针变量的时候,我们只需要把他置为NULL,在下个垃圾回收阶段中,系统会自动回收。
使用垃圾回收的时候,需要遵从一定的规范:
- 所有需要被托管的成员变量需要用宏
UPROPERTY()
标记 - 所有从UObject派生的类,才能被系统托管。非UObject派生的类可以考虑从类FGCObject派生,并实现
AddReferencedObjects
方法,或者使用智能指针 - 数组TArray的UObject类型指针元素,可以被自动托管
- Actor类型对象在不用的时候,需要手动调用Destroy。调用Destroy后不会立即消耗,也会等待下个垃圾回收阶段
编码规范
类名前缀
UE4的类名必须遵从命名规范,需要在类名前面加上正确的前缀,与之对应的C++文件名则不加前缀。否则会编译报错。
- 派生自 Actor 的类前缀为 A,如 AController。
- 派生自 UObject 的类前缀为 U,如 UComponent。
- 枚举 的前缀为 E,如 EFortificationType。
- 接口 类的前缀通常为 I,如 IAbilitySystemInterface。
- 模板 类的前缀为 T,如 TArray。
- 派生自 SWidget(Slate UI)的类前缀为 S,如 SButton。
- 其余类的前缀均为 字母 F ,如 FVector。
其他类型命名
bool类型变量需要加上b前缀,如 bCallable。
参考
- UE4 中的 C++ 编程介绍
https://docs.unrealengine.com/latest/CHN/Programming/Introduction/index.html - UE4 编码规范
https://docs.unrealengine.com/latest/CHN/Programming/Development/CodingStandard/index.html
本系列文章会和我的个人公众号同步更新,感兴趣的朋友可以关注下我的公众号:游戏引擎学习。扫下面的二维码加关注:
- UE4入门学习4:C++编程介绍
- UE4编程快速入门
- UE4入门学习-开篇
- 【UE4学习】02——C++编程快速入门
- UE4学习笔记1st:编程快速入门
- UE4 中的 C++ 编程介绍
- [C#]网络编程入门的几个介绍
- UE4学习笔记4th:编程和绑定游戏操作
- 【UE4官方文档翻译】Introduction to C++ Programming in UE4 (介绍UE4中的C++编程)
- UE4学习之关卡设计入门
- UE4入门学习1:环境搭建
- UE4入门学习2:工程结构分析
- UE4入门学习3:GamePlay框架
- UE4(一)快速上手入门学习
- UE4 介绍
- UE4蓝图编程学习 前期心得
- linux操作系统下c语言编程入门 -- (一)目录介绍
- linux操作系统下c语言编程入门 -- (2)进程介绍
- 没无线网连接WIFI
- JAVA虚拟机内存调节
- 在Windows7 64位和VS2008环境下,PrintDialog.ShowDialog不能显示打印对话框
- bootstrapValidator 的隐藏域验证
- java中邮件的发送和短信的发送
- UE4入门学习4:C++编程介绍
- 深度学习——3D识别
- mybatis关联查询,一对一,一对多
- USART分析
- Hibernate的作用是什么
- 程序员思考逻辑
- 【分享】在ubuntu server上轻松搭建ss服务端
- LeetCode练习_20170521_找最大回文串
- 腾讯社交广告高校算法大赛——心得