低阶引擎系统

子系统的启动与终止

游戏引擎是复杂软件,有多个相互合作的子系统结合而成。当引擎启动的时候,必须依次配置及初始化每个子系统。各子系统间相互形成的依赖关系,隐含地定义了每个子系统所需的启动次序。

朴素方法

明确地为各单例管理器类定义启动和终止函数,这些函数取代构建和析构函数,让构建和析构函数完全不做任何事情

class RenderManager {
public:
RenderManager() {} // 不做事情
~RenderManager() {} // 不做事情
void startUp() {} // 启动管理器
void shutDown() {} // 终止管理器
}

class PhysicsManager {} // 类似内容
class AnimationManager {} // 类似内容
class MemoryManager {} // 类似内容
class FileSystemManager {} // 类似内容

RenderManager gRenderManager;
PhysicsManager gPhysicsManager;
AnimationManager gAnimationManager;
MemoryManager gMemoryManager;
FileSystemManager gFileSystemManager;

int main(int argc, const char* argv) {
// 用正确的次序启动引擎
gMemoryManager.startup();
gFileSystemManager.startup();
gAnimationManager.startup();
gPhysicsManager.startup();

// 运行游戏
gSimulationManager.run();

// 用反向次序终止各引擎系统
gPhysicsManager.shutDown();
gAnimationManager.shutDown();
gFileSystemManager.shutDown();
gMemoryManager.shutDown();
}

此方法总是优于其他方法,因为:

  • 此方法简单又容易实现。
  • 此方法是明确的,看看代码就能立刻得知启动次序。
  • 此方法容易调试以及维护,若某子系统启动时机不够早或者过早,只需移动一行代码。

内存管理

内存对效能的影响有两个方面。

  • malloc() 或 C++ 的全局 new 运算符进行动态内存分配,是非常慢的操作。要提升效能,最佳方法是尽量避免动态分配内存,不然也可利用自制的内存分配器来大大减低分配成本。
  • 许多时候在现代 CPU 上,软件的效能受其内存访问模式主宰。将数据置于细小连续的内存块,相比把数据分散至广阔的内存地址,CPU 对前者的操作会高效很多。

堆栈分配器

malloc(),全局 new,或者是全局字节数组分配一大块连续内存,然后用指针指向堆栈的顶端,指针以下的内容是已分配的,以上的是未分配的,对于每次分配请求,将指针往上移动请求所需的字节数量即可。