之前我们已经完成了角色的移动功能,但还不具备相应的动画,所以在这一部分完成角色动画的相应设置

材料准备

PaperZD

首先需要准备的就是PaperZD这个插件,使用该插件我们可以方便的设置动画状态机,在BP_PaperCharacterBase中我们也可以看到多出来一个Animation Component组件

简单介绍一下PaperZD的三个基础模块,分别是
1. AnimationSequence:用于绑定一个2D FlipBook 2. AnimationSource:类似于一个管理器,可以集中的创建和设置AnimationSequence 3. PaperZD AnimBP:在此蓝图中设置我们的动画状态机

阅读全文 »

也算是一边看文档和各种教程,一边用蓝图做了一个简单的demo出来,不过还是感觉很多东西的云里雾里的,正好打算把部分蓝图内容转换为C++实现,所以趁这个机会记录一下

PaperCharacter

地图的制作感觉可以先放一放,因为整个流程还是比较简单的,主要就是素材的导入,给必要的Tile添加碰撞,然后自由组合即可,等后续需要和角色产生交互再统一记录吧,所以这里就先记录一下角色制作的一些关键流程

Enhanced Input

以前处理输入主要依赖于轴映射输入,但现在UE5更推荐使用增强输入来处理,个人的理解是增强输入可以解耦输入操作的逻辑,以组合的形式提高灵活性和复用性。不过我自己也没有详细了解过增强输入系统,所以就不展开介绍原理了,只简单记录一下如何使用

阅读全文 »

头文件存在的一些问题

使用头文件主要存在以下一些问题

头文件被重复处理导致编译速度过慢

宏和全局命名污染的问题

头文件依赖问题

头文件被重复处理主要是因为它是在预处理阶段直接展开的,也就是直接进行文本替换,考虑在B.h中include了A.h,然后在Utils.cppMain.cpp中都include了B.h,那么在这两个翻译单元中都会间接的包含A.h。并且,如果对A.h中的内容做了任何修改,那么其他所有包含A.h的翻译单元都需要重新编译

宏和全局命名污染的问题的原因同上,预处理阶段对头文件进行简单的文本替换导致了这个问题

阅读全文 »

我们都知道虚函数在引用语义下表现出多态,但也多了一次寻址开销

实际性能开销主要源自虚函数抑制了内联优化

首先我们先看一下以下代码的输出

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
35
36
37
38
39
40
41
42
43
44
45
46
class A {
public:
virtual void f() {
cout << "A::f()" << "\n";
}
virtual void g() {
cout << "A::g()" << "\n";
}
};
class B : public A {
public:
void f() override {
cout << "B::f()" << "\n";
}
void g() override {
cout << "B::g()" << "\n";
}
};
class C : public B {
public:
void f() override {
cout << "C::f()" << "\n";
}
void g() override {
cout << "C::g()" << "\n";
}
};

int main() {
A* a = new A();
a->f();
a->g();

B* b = new B();
*(std::uint64_t*)a = *(std::uint64_t*)b;
a->f();
a->g();

A aa = *a;
aa.f();
aa.g();

a = new C();
a->f();
a->g();
}

阅读全文 »

源码UE5启动项目的一些常见问题

之前为了学习UE5的源代码,所以就直接从源码编译了UE5来使用,不过期间也是遇到了一些奇怪的坑,在这里记录一下

环境配置问题

UE5对.NET、MSVC、Windows SDK的版本是有要求的,并不是越新越好,如果出现了环境配置上的错误,可以先打开Visual Studio Installer检查一下,推荐的配置如下

Windows SDK版本:

阅读全文 »

FS寄存器

fs寄存器记录了当前活动线程的TEB结构,具体信息如下

1
2
3
4
5
6
7
8
9
10
11
12
0x000 指向SEH链指针
0x004 线程堆栈顶部
0x008 线程堆栈底部
0x00C SubSystemTib
0x010 FiberData
0x014 ArbitraryUserPointer
0x018 FS段寄存器在内存中的镜像地址
0x020 进程PID
0x024 线程ID
0x02C 指向线程局部存储指针
0x030 PEB结构地址(进程结构)
0x034 上个错误号

阅读全文 »

C++

简述C++语言的特点

  1. 以面向对象为主,还支持泛型,函数式编程等多种编程范式
  2. C++既可以直接操作内存,也可以利用零成本抽象的特性和元编程等技巧提高运行效率
  3. C++更安全,鼓励使用RAII机制自动管理资源,减少内存泄漏风险
  4. C++是一个不断发展的语言,每3年增加一些新特性,例如C++11引入了智能指针,右值,移动语义等特性,c++20引入了module、concept、ranges等特性
阅读全文 »

资源表

资源表的结构相对复杂,采用了类似磁盘目录结构的方式保存,通常目录有3层,第1层目录类似于一个文件系统的根目录,指出了整个资源表中有多少种不同的类型(如光标、菜单、快捷键等);第2层目录指明了当前类型的资源中,有多少个资源;而第3层目录被称为资源代码页

为了便于理解,先给出一张资源表的树形结构图

阅读全文 »

之前讲解了输入表与输入地址表以及他们的工作原理,现在我们开始分析输出表与重定位表

输出表

创建一个DLL时,实际上创建了一组能让exe或其他DLL调用的函数,而PE装载器将根据DLL文件中的输出信息修正正被执行文件中的IAT。通常exe文件中不存在输出表(并不绝对),而大部分DLL文件中则存在输出表

输出表的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; // 旗标,未使用,总是为0
DWORD TimeDateStamp;
WORD MajorVersion; // 主版本号,一般为0
WORD MinorVersion; // 次版本号,一般为0
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions;
DWORD AddressOfNames;
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY
阅读全文 »

之前已经对PE文件的总体结构进行了解析,但PE文件中的很多重要的数据还存放在各类数据表中,因此我们还需要对这些表信息进行解析,这里主要包块输入表与输入地址表、输出表、重定位表、资源表五个部分

输入表与输入地址表

什么是输入表

可执行文件使用来自其他DLL的代码与数据的行为称为输入,当PE文件载入内存时,Windows加载器的工作之一就是找到这些输入的函数与数据,并让文件可以使用这些代码与数据的正确地址,而这个过程正是通过输入表(Import Table)完成的,输入表中保存了输入的函数名和这些函数所在的DLL名称

阅读全文 »
0%