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

时间:2011-06-24 05:03:18

标签: c++ oop architecture 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

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

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

  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

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

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

    谢谢大家,非常感谢任何帮助!

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

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

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

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

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

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

    哇,这就是现在的问题。随着我的进步,我会添加更多或提出新问题。非常感谢你的帮助。

2 个答案:

答案 0 :(得分:6)

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

将状态与引擎分开会增加额外的复杂性,并使实现变得更加棘手。

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

您的选择是:

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

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

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

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

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

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

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

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

default:
    gcc [...]

all:
    gcc [...]
    gcc [...]
    <...>

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

你应该知道makefile很快就变得非常繁琐,而且autotools这样的解决方案通常是首选。

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

修改

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

您似乎非常清楚自己的目标,这是最重要的部分。根据你的说法,你可以更好地将游戏引擎作为你自己的静态库,这是许多游戏链接的。

然后你的引擎会提供一个界面来注册状态,游戏将使用这些状态说“这是我的状态叫做 title ”,然后告诉引擎“切换到名为 title的状态“只要有需要。

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

引擎将是一个自己的项目,游戏项目只需要在 / lib 中有一个引擎库的副本。然后,您将在编译时将引擎静态链接到您的游戏。

如果您想了解有关如何构建状态对象的更多详细信息,请与我们联系。


答案 1 :(得分:2)

你提出的许多问题都没有明确的答案,这通常是个人偏好。

我从你的问题中得知你也编译了你的标题,你不应该编译标题,它们应该只包含在.cpp文件和其他标题中。然后它们被编译为cpp的一部分。文件应该只包含他们真正需要的标题。

只要您的项目很小,保持一个目录中的每个目录通常都是最好的,但如果您知道它会增长,那么建立一个好的目录结构是个好主意。像你一样从实际的游戏中分离潜在的可重复使用的GameEngine是一件好事。

当该部分将在其他项目中重用或者当您的项目变得如此之大以至于.o文件的数量变得非常高时,创建库是有用的。因此,如果这适用于GameEngine,请将其设为lib。对于像游戏引擎这样的可重用项目,将标题保存在单独的目录中通常也很有用。因为依赖于它的项目只需要头文件和库,所以它们不需要其余的源代码。

当项目使用单独的源目录变大时,中间(.o)和最终可执行文件有助于保持文件的可管理性,因为存储.o,你的源代码通常会将src目录中的文件数量增加50%。

如果你想把它设置得很好,你可能想看看autoconf和automake。他们有一个陡峭的学习曲线,但他们将从你手中取出大量的Makefile。这些是创建在许多开源软件包的源代码发行版中找到的配置脚本的工具。