构建基于状态的游戏引擎,Makefile结构有帮助吗?

Sti*_*CPP 6 c++ architecture oop makefile

我正在研究一个基于状态的游戏引擎,并且有一些我很满意的开始.

有一个抽象类GameState.hpp,我使用的是虚拟方法(init,run,pause等...).

GameEngine.cpp/hpp是一个包含一堆GameState对象的类,它通过运行当前状态的相关方法来设置游戏循环.

我的测试游戏TestGame.cpp创建了一个GameEngine对象并推送了一个TestState实例并运行等等...所有工作正如我所料.

我想构建我的源代码树而不是编译来自同一目录的所有内容,并考虑以下内容,因为每个游戏会有多个状态:

src/
  +Engine/
    +GameEngine.cpp
    +GameEngine.hpp
    +GameState.hpp
  +TestGame/
    +States/
      +TestState.cpp
      +TestState.hpp
    +TestGame.cpp
Run Code Online (Sandbox Code Playgroud)

在构建时,我不确定我是否理解需要编译什么,以及编译对象应该去哪里.

到目前为止,我最初的想法是:

  1. 使用GameState.hpp编译GameEngine.cpp/hpp,给出GameEngine.o

  2. 编译每个游戏状态,例如.TestState.hpp中的TestState.cpp/hpp给出了TestState.o

  3. 使用GameEngine.o/hpp,GameState.hpp,TestState.o/hpp(以及任何其他状态)编译TestGame.cpp/hpp,给出TestGame.bin

我是在正确的轨道上吗?GameEngine应该构建一个lib,还是一个普通的.o好吗?我是否需要在每个编译中包含标题仍然有点模糊.此外,每个编译的输出文件是否与源位于同一目录中,还是应该位于结构化bin /目录中?

我会玩游戏并发布一些Makefile尝试和输出.让我知道如果我应该发布代码,总共可能有200行.没有实际的图形实现等......目前只是一个框架.

谢谢你们,任何帮助都非常感谢!

编辑:感谢您的快速回复.我已阅读下面的评论,并希望提供更新并清除一些内容.

首先,我正在研究autotools,但这主要是一个学习项目,其中一部分是grokking makefile.我也来自Java背景,所以我真的想要了解我正在构建的内容以及我的项目如何组合在一起.如上所述,我甚至不知道某些东西应该是库还是只是在编译时指向.

我的目标概述:我认为引擎几乎是一个子项目.即使它的简单(<10个文件),它将加载我认为的'状态'并循环状态定义的[ 句柄事件,更新,显示 ]方法.我有一个算法,旨在每秒进行一定数量的更新,同时根据需要改变帧速率.

例如状态显示方法将利用引擎的SDL支持的显示功能(可能是一个tile引擎,状态可以说'加载这些资源,显示这些tile',或者一个widget库,无论......)来呈现代表游戏世界模型.在处理事件的方法,可以用一个抽象的键盘接口.我希望能够在引擎中添加这样的功能. Update将管理代表游戏世界的模型.它将跟踪世界中的物体(场景,玩家和np),根据物理和碰撞检测应用运动等...

我想我希望能够构建这个并且只是将对象(和标题?)包含在我正在处理的游戏中.无论是'将引擎源dir复制到游戏项目的根目录并将其添加到主Makefile中,一起构建它',或者"只要它发生变化就在引擎上运行make",用副本构建游戏项目最新的引擎对象(,共享对象,其他什么?)和标题',对于我使用一个引擎处理多个小游戏项目最简单的方法是什么?我有点想让自己站起来,所以我可以随意玩游戏,因为我有它们,比如2周的编码等等...

状态表示任何不同的视图和一组交互.引擎具有LIFO状态堆栈,因此简单的游戏可以在堆栈上具有以下状态:DrivingMode - PauseMenu - 设置实际游戏具有GameEngine的实例,并且将添加DrivingMode以启动游戏.用户暂停,暂停DrivingMode状态并按下PauseMenu状态(在push时运行其init,run等等).在这里,用户选择暂停PauseMenu状态并加载设置的设置......当它们退出时,弹出状态(清理等等......首先运行),并恢复最高状态.

哇,这就是现在的堆积.随着我的进步,我会添加更多或提出新问题.再次感谢你的帮助.

alx*_*xbl 6

首先,你真的需要模态化的状态吗?如果您打算为特定目的编写引擎,那么您的状态可能不会发生太大变化,因此可能应该编译为引擎本身的一部分.

将状态与引擎分开将增加额外的复杂性并使实现更加棘手.

下一个问题是你是否希望你的引擎成为一个游戏链接以便使用的库,或者引擎的源是否被放入游戏的子文件夹中,并随之编译.

你的选择是:

  • 将引擎和状态编译为一个库(可能是您链接游戏的静态库)
  • 将引擎编译为静态库,然后将状态编译为可动态链接的共享对象(这将适合模块化状态选项,但会增加很多复杂性)
  • 将整个引擎+游戏编译成一个大的可执行文件,消除了任何库链接的需要(但也使引擎和游戏更加耦合)

在我看来,选项1看起来是最好的.

使用任一选项,我都会将引擎保留在游戏的子目录中.到目前为止,您的文件结构看起来非常可靠,您应该坚持下去.

如果您仍然选择允许游戏定义自己的状态,那么您将需要使用选项2并在引擎中实现一些核心状态(可能类似于INIT,MAIN_MENU,SHUT_DOWN)以及类似"插件"的内容经理",在这种情况下将负责用游戏引擎注册游戏的状态.

然后可以将每个状态单独编译为共享对象(.so),并在加载游戏时动态加载.

至于Makefiles,它实际上取决于你打算使用什么(CMake,GNU autotools等)

GNU Makefile有一个非常简单的语法,但学习使用它们可能有点棘手.

它们由如下定义的目标组成:

default:
    gcc [...]

all:
    gcc [...]
    gcc [...]
    <...>
Run Code Online (Sandbox Code Playgroud)

调用make时没有参数,第一个目标是默认目标我不会深入描述如何使用makefile(对于GNU Make:this link)

您应该知道makefile很快就变得难以维护,并且通常首选像autotools这样的解决方案.

请注意,autotools是一个非常庞大的系统,由许多程序组成,学习起来非常耗时.如果您想要关注的是开发游戏引擎,我强烈建议使用像Code :: blocks这样的项目IDE 来为您编写代码并进行链接.

编辑

为了响应您的编辑,我将添加以下内容:

你似乎非常清楚自己的目标,这是最重要的部分.根据你所说的,你会更好,因为游戏引擎是你自己的静态库,你的许多游戏链接.

然后你的引擎会提供一个接口来注册状态,游戏将使用这些状态说"这是我的状态称为标题 ",然后在需要时告诉引擎"切换到称为标题的状态".

您可能想要考虑的一件事是拥有一些基本状态,所有游戏都必须注册(由引擎本身强加).

然后引擎将是它自己的项目,并且游戏项目将简单地在/ lib中具有引擎库的副本.然后,您将在编译时将引擎静态链接到您的游戏.

如果您想了解有关如何构建状态对象的更多详细信息,请告诉我们.