有很多不同的方法,所以这里有一个如何解决这个问题。
私人构造函数
通过使Foo
的构造函数为private,您可以确保只有friend
类可以分配对象的实例。这种方法在编译时就已经抱怨了。一个缺点是您必须列出允许创建Foo
实例的所有类。如果我们谈论几个课程,这将是一个合适的方式。
class Foo
{
private:
Foo() {}
friend class Engine;
};
class Engine
{
Foo f; // OK
};
class ForeignClass
{
Foo f; // FAILED to create
};
void main()
{
Foo f; // FAILED to create
}
如果您不包含标题,那么它们将不会“可见”。因此,只包括您要使用的类的标题。
在开发游戏引擎项目时,对其设计过程有相当的考虑。最重要的目标之一是将该项目设计为尽可能模块化和可重用。您的所有Engine组件都应该在他们自己的项目中,并且所有Game内容也应该在他们自己的项目中。这样,您只需创建一个新的游戏项目,就可以重用Game Engine项目来创建多个游戏。这样您就不必从引擎本身中删除游戏源代码并破坏引擎。这将节省大量的时间,工作和麻烦。考虑这种设计模式。我在下面向您展示的项目设计流程是使用OpenGL API。
引擎项目:一个静态库,包含加载图像,声音,处理着色器,将对象渲染到屏幕以及处理网络所需的所有类。
- 引擎:此类将是抽象的,它将创建窗口,设置游戏分辨率并初始化DirectX或OpenGL或任何其他Graphics API。位于其自己的项目中的Game类将继承此。
- AssetStorage:管理所有资产内存的类。
- 批处理:创建一组三角形条,扇形等的类,用于将顶点发送到视频卡。
- BatchManager:管理批次的类。
- CommonStructs:仅包含结构的头文件文件&通常在引擎内的多个类中使用的枚举。
- ExceptionHandler:处理所有异常的类。
- FontManager:管理从纹理文件加载的字体的类。
- 记录器:当需要显示或记录错误,警告或重要消息时,将记录到文件或控制台的类。
- 设置:存储用户设置的类,例如分辨率,鼠标灵敏度等。
- Singleton:一个抽象基类,用于确保每次运行应用程序时只能存在一次特定的类。例如,任何Manger类类型,Engine :: Game都是Singleton对象的一种类型。
- 实用程序:一个不是对象但包含许多有用函数的类,它们被定义为静态的。要使用其中一个,您需要包含* .h文件并调用
Utility::convertToUnsigned( string );
中的任何方法
- 动画:所有动画类型将派生自的抽象类。
- AnimationGuiMover:一种负责移动Gui对象的动画。
- AnimationManager:管理所有动画的管理员类。
- AnimationTimer:一种基于set timer的动画对象。
- FileHandler:特定文件处理程序类型将派生自
的基类
- MkoFileReader:读取用户定义的2D或3D对象。
- TextFileReader:读取文本文件。
- TextFileWriter:写入文本文件。
- TextureFileReader:在纹理文件中读取:png,tga,bmp,jpeg等。
- Array2d:Mko对象类型。
- BaseMko:Mko对象的基类。
- FontFile:用于创建字体的2D图像文件。
- Image2D:另一个Mko对象类型。
- Surface3d:另一个Mko对象类型
- VisualMko:任何具有视觉渲染关联的Mko对象,例如精灵或3D模型。
- ShaderManager:处理所有着色器的管理器类。
- ShaderProgramSettings:用于根据属性和制服设置OpenGL着色器程序 - 严重依赖于模板。
- ShaderVariable:这可以是属性或统一,并且在很大程度上依赖于模板。
- BlockProcess:用于阻止进程的类:这样我们只需要运行一个游戏实例,因此在Windows中它将根据Windows句柄和应用程序名称创建一个互斥锁,从而防止多次执行此应用程序。 / LI>
- BlockThread:用于在处理多线程时创建和销毁关键部分。
- OpenglThread:用于处理OpenGL的特定线程类
- VolatileLocker:与BlockThread类似,但与易失性数据类型一起使用。
- Gui系统: 这是类的层次结构;一些是抽象基类
- GuiCompositeElement:抽象基类
- GuiElement:抽象基类
- GuiImage:继承自GuiRenderable
- GuiImageElement:不从任何其他类继承。
- GuiLabel:继承自GuiText
- GuiLayout:所有布局类型的抽象基类 - 从GuiRenderable继承
- GuiLayoutAbsolute:继承自GuiLayout
- GuiLayoutGrid:继承自GuiLayout
- GuiLayoutSlices:继承自GuiLayout
- GuiLayoutStack:继承自GuiLayout
- GuiLoader:读取gui文本文件的类解析数据并构造所有gui对象,以减少在gui系统中更改数据时的构建时间。
- GuiRenderable:从GuiCompositeElement继承,但也是一个抽象基类
- GuiScreen:不能成为另一个Gui Type的孩子但是包含Gui孩子 - 继承自GuiCompositeElement
- GuiText:继承自GuiRenderable
- GuiTextArea:继承自GuiText
- 更多信息 声音处理,网络等对象。
游戏项目:包含仅限游戏内容,例如要加载的资源,加载级别,如何处理键盘鼠标等的用户输入,以及特定于此游戏的任何内容。
- main.cpp - 主要入口点。
- 游戏:游戏类启动游戏循环,初始化所有设置,构建所有必需的对象等,并处理用户输入。
- GameState:在播放,暂停等之间切换。状态机。
- 属性:特定于此游戏的属性。
- 更多信息:此项目远未完成
正如您所看到的,这是为了将所有游戏逻辑与引擎逻辑分离,将游戏引擎的概念设计为尽可能通用和模块化。通过这种类型的设计过程,使用相同的现有引擎构建完全不同的游戏所需要做的就是删除Game项目并添加新项目,将所有资产存储在相应的目录中并编写必要的代码新游戏。这样一来,人们不必担心潜入Engine项目,寻找成千上万行代码,试图确定什么是引擎代码,什么是Game Code,很可能会破坏引擎。这种设计流程将节省许多未来的麻烦和宝贵的时间。
如您所见,Engine类负责创建Window,设置Graphics API,创建Manager Objects以及加载和呈现资源的能力。由于这个Engine类是抽象的,因此Game类必须继承它并使用纯虚方法来处理键盘和键盘。鼠标输入确保每个游戏必须实现如何处理用户控件。该项目已经开发了几年,还有更多的工作需要完成。与任何工业标准使用引擎相比,这个解决方案/游戏引擎相当轻巧,我已经扩展了超过100,000行代码,我甚至没有提到任何关于游戏逻辑,评分,级别进展的内容,物理学,也不是AI。