头图

游戏引擎架构底层系统篇---1.子系统的加载与卸载

KDYH

所有游戏引擎都需要底层系统的支持,来做一些平凡琐碎但是又必须要做的事情。如:加载和卸载子系统,配置引擎和游戏的特性,管理引擎的内存,对游戏中使用的各种资源的访问方式,游戏开发中的调试工具等。所以从现在开始,我们就来看一些游戏引擎中的底层系统并尝试实现他们吧。


子系统的加载和卸载

游戏引擎是一个由一大堆互相交互的系统所构成的,所以当引擎启动的时候,子系统必须要按照一种特定的顺序来进行配置和初始化(因为子系统之间存在一定的依赖性)。子系统之间的依赖性决定了这个特定的加载顺序。接下来我们就开始看看该如何解决这一问题。

C++

因为我们决定使用的语言是C++,所以我们先来考察一下C++的特性能否为我们解决这个加载顺序的问题。

在windows中,C++中的global和static类型的对象会在main()函数调用之前就构造完成,但是这些对象会以一种不可预测的顺序构造,与之相对应的析构函数会在main()结束后以一种不可预测的顺序调用。

class RenderManager
{
public:
    RenderManager() {
        //start up the manager
    }

    ~RenderManager() {
        //shut down the manager
    }
};
//singleton instance
static RenderManager gRenderManager;

所以global,static 不行


通过命令来构建

那既然直接用C++的特性解决不了问题,就只好绕个圈子。我们知道,一个在函数中的静态变量是不会在main()函数和它本身所在的函数调用之前构造的。所以我们可以通过在函数中申明静态变量来控制我们的全局单例。

来改进一下之前的代码吧!

class RenderManager
{
public:
    static RenderManager& get() {
        static RenderManager sSingleton;
        return sSingleton;
    }

    RenderManager() {
        //start up the manager
    }

    ~RenderManager() {
        //shut down the manager
    }
};

这一次可以了吗?如果我们能控制get()函数何时运行,那么就可以控制这个构造顺序了。
但是问题来了,怎么控制析构的顺序呢?并且很难精准预测到RenderManager何时被构造。

所以这种方式也不太行

一种简单的可以工作的方式

我们仍然坚持子系统的单例模式,那就可以直接粗暴的显式定义start-up和shut-down函数来加载每一个子系统单例,他们取代了构造函数和析构函数。
此时,我们就可以显式的的规定子模块在main()函数中何时被构造,何时被析构,从而做到以一定的顺序被加载和卸载。而构造函数和析构函数则什么都不做。

class RenderManager
{
public:
    RenderManager() {
        //do nothing
    }

    ~RenderManager() {
        //do nothing
    }

    void StartUp() {
        //start up the manager
    }

    void ShutDown() {
        //shut down the manager
    }
};
RenderManager gRenderManager;
PhysicsManager gPhysicsManager;
//...

int main(int argc, const char* argv) 
{
    gRenderManager.StartUp();
    //...
    gPhysicsManager.StartUp();

    //...

    gPhysicsManager.ShutDown();
    //...
    gRenderManager.ShutDown();

    return 0;
}
阅读 966
1 声望
0 粉丝
0 条评论
1 声望
0 粉丝
文章目录
宣传栏