核心类型¶
Godot有一组丰富的类和模板组成了它的核心,所有的东西都建立在它们之上。
这篇参考文献将试图列出它们,以便更好地理解它们。
定义¶
godot使用标准的c98数据类型,例如 uint8_t
, uint32_t
, int64_t
等等,现在每个编译器都支持。重新设计轮子并不是很有趣,因为它使代码更难阅读。
一般来说,除非使用大型结构或数组,否则不要为给定任务使用最有效的数据类型。 int
在大多数代码中使用,除非必要。这是因为现在每个设备都至少有一个32位总线,并且可以在一个周期内完成这些操作。它也使代码更加可读。
对于文件或内存大小, size_t
使用,保证为64位。
对于Unicode字符,使用chartype而不是wchar_t,因为许多体系结构有4个字节长的wchar_t,其中可能需要2个字节。但是,在默认情况下,这不是强制的,chartype直接映射到wchar_t。
参考文献:¶
记忆模型¶
PC是一个很好的体系结构。计算机通常有千兆字节的RAM、千兆字节的存储空间和千兆赫兹的CPU,当应用程序需要更多的资源时,操作系统将替换掉不活动的资源。其他的架构(如移动或控制台)通常比较有限。
最常见的内存模型是堆,在堆中,应用程序将请求一个内存区域,底层操作系统将尝试将其放在某个位置并返回。这往往是最好的工作,是灵活的,但随着时间的推移和滥用,这可以导致分割。
分段会缓慢地产生对于大多数常见分配来说太小的孔,从而浪费内存。有很多关于堆和分段的文献,所以这个主题在这里不会得到进一步的发展。现代操作系统使用分页内存,这有助于减轻分割问题,但不能解决它。
然而,在许多研究和测试中,都表明,如果有足够的内存,那么如果最大分配大小低于给定的阈值(与最大堆大小和打算不使用的内存比例成比例),那么随着时间的推移,分段将不会是一个问题,因为它将保持不变。换句话说,让10-20%的内存空闲,然后执行所有小的分配,这样就可以了。
Godot确保可以动态分配的所有对象都很小(最多不到几个KB)。但是,如果分配太大(如图像、网格几何或大型数组),会发生什么情况?在这种情况下,godot可以选择使用动态内存池。需要锁定此内存才能访问,如果分配耗尽内存,则池将根据需要重新排列和压缩。根据游戏的需要,程序员可以配置动态内存池大小。
分配内存¶
Godot有很多工具可以跟踪游戏中的内存使用情况,特别是在调试期间。因此,不应该使用常规的C和C++库调用。相反,还提供了其他一些。
对于C样式的分配,godot提供了一些宏:
memalloc()
memrealloc()
memfree()
这相当于通常的malloc,realloc,不受标准C库的限制。
对于C++风格的分配,提供了特殊的宏:
memnew( Class / Class(args) )
memdelete( instance )
memnew_arr( Class , amount )
memdelete_arr( pointer to array )
相当于新建、删除、新建 []删除[] .
MeMeNe/MeMeDelk也使用了一点C++魔术,并在创建对象后立即通知对象,并在删除前立即通知它们。
对于动态内存,提供poolvector<>模板。POOLVector是一个标准的向量类,与C++标准库中的向量非常类似。要创建池向量缓冲区,请使用以下命令:
PoolVector<int> data;
可以使用[]运算符访问poolvector,并为此存在一些助手:
PoolVector<int>::Read r = data.read()
int someint = r[4]
PoolVector<int>::Write w = data.write()
w[4] = 22;
这些操作允许从池向量快速读/写,并将其保持锁定,直到它们超出范围。但是,poolvector应该用于小型的动态内存操作,因为read()和write()对于大量访问来说速度太慢。
容器¶
Godot还提供一套通用容器:
矢量
表
集合
地图
它们是简单的,目的是尽可能的小,因为C++中的模板经常被内联,并且在调试符号和代码中都使二进制大小变得更胖。列表、集合和映射可以使用指针进行迭代,如下所示:
for(List<int>::Element *E=somelist.front();E;E=E->next()) {
print_line(E->get()); //print the element
}
Vector<>类还有一些很好的特性:
它是在写的时候复制的,所以只要不修改,复制它是很便宜的。
通过在引用计数器上使用原子操作,它支持多线程。
StringName¶
字符串名称类似于字符串,但它们是唯一的。从字符串创建StringName会为所有相等的字符串生成唯一的内部指针。字符串名称对于使用字符串作为标识符很有用,因为比较字符串基本上就是比较指针。
创建一个StringName(尤其是一个新的)很慢,但是比较很快。