c++ - 构建基于状态的游戏引擎和 Makefile 结构有帮助吗?

标签 c++ oop architecture makefile

我正在开发基于状态的游戏引擎,并且有一些我很满意的开始。

有一个抽象类 GameState.hpp,其中包含我使用的虚拟方法(初始化、运行、暂停等...)。

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

我的测试游戏 TestGame.cpp 创建一个 GameEngine 对象并推送一个 TestState 实例并运行等......一切都按我的预期工作。

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

src/
  +Engine/
    +GameEngine.cpp
    +GameEngine.hpp
    +GameState.hpp
  +TestGame/
    +States/
      +TestState.cpp
      +TestState.hpp
    +TestGame.cpp

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

到目前为止,我的初步想法是:
  • 用 GameState.hpp 编译 GameEngine.cpp/hpp,得到 GameEngine.o
  • 编译每个游戏状态,例如。 TestState.cpp/hpp 和 GameState.hpp,给出 TestState.o
  • 使用 GameEngine.o/hpp、GameState.hpp、TestState.o/hpp(和任何其他状态)编译 TestGame.cpp/hpp,得到 TestGame.bin

  • 我在正确的轨道上吗? GameEngine 应该构建一个库,还是一个常规的 .o 可以?我对是否需要在每次编译中都包含头文件仍然有些模糊。此外,每个编译的输出文件是否与源文件位于同一目录中,还是应该位于结构化的 bin/目录中?

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

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

    编辑:感谢人们的快速 react 。我已经阅读了下面的评论,并想提供更新并澄清一些事情。

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

    我的目标概述:我几乎将引擎视为一个子项目。尽管它很简单(<10 个文件),但它会加载我认为的“状态”并循环 []处理事件、更新、显示 ] state 定义的方法。我有一个算法,旨在每秒更新恒定数量,同时根据需要改变帧速率。

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

    我想我希望能够构建它并且只将对象(和标题?)包含在我正在开发的游戏中。无论是
    '将引擎源目录复制到游戏项目的根目录,并将其添加到主 Makefile 中,一起构建它',或
    '每当引擎发生变化时在引擎上运行 make,使用最新引擎对象(、共享对象、其他东西?)和标题的拷贝构建游戏项目',
    使用一个引擎处理多个小型游戏项目对我来说最简单的是什么?我有点想设置自己,这样我就可以在我拥有随机游戏创意的情况下开始运作,例如 2 周的编码竞赛等......

    状态代表任何不同的 View 和交互集。引擎有一个 LIFO 状态堆栈,所以一个简单的游戏可能在堆栈上有以下状态:
    驾驶模式 - 暂停菜单 - 设置
    实际游戏有一个 GameEngine 实例,并且会添加 DrivingMode 来启动游戏。用户暂停,这会暂停DrivingMode 状态并推送PauseMenu 状态(在推送时运行其init、run 等)。在这里,用户选择暂停 PauseMenu 状态并加载设置的设置......当他们退出时,状态被弹出(清理等......首先运行),并恢复顶部状态。

    哇,现在是一堆。随着我的进步,我会添加更多或提出新问题。再次非常感谢您的帮助。

    最佳答案

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

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

    下一个问题是您是否希望您的引擎成为游戏链接以便使用的库,或者是否将引擎的源放在游戏的子文件夹中,并与它一起编译。

    您的选择是:

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

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

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

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

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

    至于 Makefiles,这真的取决于你打算使用什么(CMake、GNU autotools 等)

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

    它们由定义如下的目标组成:
    default:
        gcc [...]
    
    all:
        gcc [...]
        gcc [...]
        <...>
    

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

    您应该知道,makefile 很快就会变得非常繁琐,而像 autotools 这样的解决方案也是如此。通常是首选。

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

    编辑

    针对您的编辑,我将添加以下内容:

    你似乎很清楚自己要去哪里,这是最重要的部分。从你所说的来看,你会更好地拥有游戏引擎,因为它是你的许多游戏链接的自己的静态库。

    然后,您的引擎将提供一个接口(interface)来注册状态,游戏将使用该接口(interface)来表示“这是我的名为 title 的状态”,然后在需要时告诉引擎“切换到名为 title 的状态”。

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

    引擎将成为它自己的项目,例如,游戏项目将在/lib 中简单地拥有引擎库的拷贝。然后,您将在编译时将引擎静态链接到您的游戏。

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

    关于c++ - 构建基于状态的游戏引擎和 Makefile 结构有帮助吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6463602/

    相关文章:

    c++ - SFINAE on Error in Dependent Type 导致意外的硬错误

    c++ - error() 函数在哪个库中?

    c++ - 在 ns 2.34 (Jiazi YI ns 2.29) 上添加 mp-olsr 时出现编译错误

    oop - 编程语言背后是否有任何数学模型或理论?

    c# - 将测试驱动开发应用于紧密耦合的架构

    c++ - 使用尾递归查找数组的最小元素

    C# |= 和 &= 运算符

    python - 为什么 Python 深受动画行业从业人员的喜爱?

    java - Spring Boot Multi-Tenancy 架构中的表同步

    wcf - 第一次架构?