c++和蓝图说明
蓝图是unreal提供给我们的一个写游戏的最重要的“武器”,因为只要会了蓝图,不会编程的小白都可以写出自己的游戏。但是我们也可以通过ue把蓝图工程转成c++工程。
而c++则是使用编程语言来编写代码,实现相应的功能,但是也有一些功能是c++代码实现不了的,例如:动画,shader,模型。
c++于蓝图的优点就是性能突出,可控性更多,但是就是要自己编写代码,耗的时间就非常多,但是蓝图多消耗的性能也就多一点,对于简单的功能完全没有必要写c++代码。
虚幻中类的层级结构
object类 : 是一个最基础的父类,只用来存放数据。
actor类 : 是一个有视觉效果的,能放置到场景里面的类。
pawn类 : 可以被控制器持有的类,有行为动作,能运动。
character类 : 有角色移动或者是行为的功能。
而这四个类是属于继承的关系, 顺序是:object->actor->pawn->character
一般来说创建玩家,我们都是用的pawn类来创建。
虚幻中游戏的层级结构
package:相当于工程文件本身。有一个world。里面包含很多东西,例如meshes,texture。
world:游戏世界,一个世界可以有多个level。
level:level就是关卡。一个关卡有多个actor。
actor:就是对象,也就是level场景里面的不同的东西。一个actor可以有多个component。
component:组件,可以使脚本组件,也可以是构成的组件,例如:台灯里面有灯泡,灯罩等等。
ue中的反射和垃圾回收机制
C++本身并不支持任何的反射形式,所以虚幻引擎使用自身的一套系统来收集、查询和管理C++相关的类、结构体、函数、成员变量以及枚举器等信息。作用于编辑器中的细节面板、序列化、垃圾收集、网络应答以及蓝图与C++的通信等。
我们在编写代码的时候,需要事先标记那些你想要被反射系统访问的任何类型和属性,然后Unreal Header Tool (UHT) 工具将会在你编译项目的时候收集这些信息。如果要使用标记的功能,我们需要添加
#include “FileName.generated.h”
放在我们编写文件的开头,这样UHT才会考虑这个文件。我们可以使用UENUM(), UCLASS(), USTRUCT(), UFUNCTION()和UPROPERTY()在头文件中来注明不同的(需要加入反射机制的)类型和成员变量,这些宏的每一个都要放在类型或者成员变量定义的前面,并且可以包含一些指定的关键字参数。
来看StrategyGame的例子:
1 | ////////////////////////////////////////////////////////////////////////// |
使用EditAnyWhere这个参数的时候要注意,不能再指针上面使用这个参数,否则在蓝图细节面板会有非常不方便的问题。
GENERATED_UCLASS_BODY() / GENERATED_USTRUCT_BODY()这两个宏要求被添加到对应的类或者结构体中,因为他们会在类的定义体中添加额外的函数或者类型别名.
Unreal Build Tool (UBT) 工具和 Unreal Header Tool (UHT)工具一致合作来产生运行时反射所需的数据,UBT工具必须去浏览头文件来作为它的工作,它需要记录那些至少包含一个反射类型属性的头文件的模块,如果这些头文件在编译结束时发现有改变,则UHT工具将会被调用来收集和更新反射数据,UHT工具解析那些头文件,然后建立一个反射数据的集合,并且产生包含反射数据(产生到per-module.generated.inl文件中)的C++代码、种类繁多的帮助和程序块(在per-header.generated.h文件中)。
UNREAL PROPERTY SYSTEM 的类型继承体系:
UField(Base class of reflection data objects.)
UStruct(Base class for all UObject types that contain fields. 就是 aggregate structures(anything that contains other members) 的基类)
UClass (C++ class : contain functions or properties: UTypeName::StaticClass() )
UScriptStruct (C++ struct 重要重要!! : limited to just properties: FTypeName::StaticStruct() )
UFunction (C++ function : limited to just properties)
UEnum (C++ enumeration)
UProperty (C++ member variable or function parameter)
(Many subclasses for different types)
获取类类型 : UTypeName::StaticClass() 或者 Instance->GetClass()
获取结构体类型 : FTypeName::StaticStruct()
而ue4中的垃圾回收,当一个对象没有指针去指向它,那么就说明这个对象时垃圾对象,所以会被回收。
gameplay框架
gameplay框架是ue4官方提供给我们使用的一个快速构建游戏架构的框架。
上面这张图片是这个框架的基本结构图。
控制器类是继承aactor类,作用是控制pawn的行为的,分为AIController和PlayerController。AIController是用来控制非玩家的人物,例如:怪物。PlayerController则是控制玩家的,可以控制很多东西,例如:HUD(平头显示信息),用户输入,以及相机。
GameMode(游戏模式)。处理游戏的规则,只存在与服务器端,因此客户端相关的逻辑不能存放在GameMode中。
GameState(游戏状态)。记录游戏的数据,比如当前游戏的进度,世界任务的完成状态等,会自动同步到各个客户端。
PlayerState(玩家状态)。记录玩家个人的数据,比如名字分数等,会自动同步到各个客户端。
CreateDefaultSubobject()函数
在虚幻引擎里面创建一个静态网格体是非常简单的,只需要鼠标点击转换就可以了,但是我们在c++里面应该怎么创建静态网格体呢,其实可以用CreateDefaultSubobject函数。
我们只需要在这个函数里面把泛型写成UStaticMeshComponent就可以了。例如
1 | UStaticMeshComponent* Actor = CreateDefaultSubobject<UStaticMeshComponent>(Text("")); |
我们使用这个函数还可以创建蓝图类的默认根组件,使用USceneComponent泛型。
但是我们使用这个函数是有限制的,我们必须在无参构造函数里面调用才行,否则会crash,并且必须使用指针类型接收函数返回值,否则crash。
subobject是什么东西呢?英文翻译是:子物件,子对象的意思。我们从字面意思上也可以看得出,它就是我们创建对象的子对象,如果我们创建ULevel对象,那么子对象就是AActor,AActor就是subobject,我们就可以在ULevel的无参构造函数里面调用CreateDefaultSubobject()函数创建AActor对象。它和component的区别就是,component没有层级关系,它只是表示一个组件而已,没有子父的关系在里面。
DeltaTime的作用
我们在创建一个c++类的时候,我们可以看见系统给我们自动创建了一个Tick函数,里面有一个DeltaTime的参数。我们可以知道Tick函数是系统每帧调用的函数,那么DeltaTime参数就一定有用的。
先说DeltaTime参数是什么吧,DeltaTime参数是相邻两帧之间的时间。
举个例子:fps代表着一秒多少帧,如果我的电脑玩英雄联盟fps是120,那么就是一秒120帧,DeltaTime就等于1/120秒。
DeltaTime的作用就是用来平衡两个电脑性能不同,结果相同的。同样举个例子:如果我们设置一帧走1厘米,在网络游戏对战里面,是即时对战,我们不能因为一个人的电脑好就让它走的比别人更快吧,所以我们通过乘上DeltaTime,就可以取消两个电脑性能之间的差距。其实就是一个帧数乘以它的倒数,就是等于本身这个原理。