ue4的初始入门知识

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//////////////////////////////////////////////////////////////////////////
// Base class for mobile units (soldiers)
#include "StrategyTypes.h"
#include "StrategyChar.generated.h"

UCLASS(Abstract)
class AStrategyChar : public ACharacter, public IStrategyTeamInterface
{
GENERATED_UCLASS_BODY()

// 当前变量的值能够在编辑器的任意一个细节面板中编辑,并且显示在’Pawn’分组中
UPROPERTY(EditAnywhere, Category=Pawn)
int32 ResourcesToGather;

// 当前函数可以被蓝图函数里面调用
UFUNCTION(BlueprintCallable, Category=Attachment)
void SetWeaponAttachment(class UStrategyAttachment* Weapon);

UFUNCTION(BlueprintCallable, Category=Attachment)
bool IsWeaponAttached();

protected:
// 当前变量的值能够在编辑器的蓝图类细节面板中编辑
UPROPERTY(EditDefaultsOnly, Category=Pawn)
UAnimMontage* MeleeAnim;

/** Armor attachment slot */
UPROPERTY()
UStrategyAttachment* ArmorSlot;

/** team number */
uint8 MyTeamNum;
[more code omitted]
};

使用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官方提供给我们使用的一个快速构建游戏架构的框架。

avatar

上面这张图片是这个框架的基本结构图。
控制器类是继承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,就可以取消两个电脑性能之间的差距。其实就是一个帧数乘以它的倒数,就是等于本身这个原理。