构建一个基于状态的游戏引擎,以及Makefile结构帮助
Structuring a state based game engine, and Makefile structure help?
我正在开发一个基于状态的游戏引擎,首先我对它感到满意。
有一个抽象类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
在构建时,我不确定是否了解需要用什么编译什么,以及编译后的对象应该放在哪里。
到目前为止,我最初的想法是:
用GameState.hpp编译GameEngine.cpp/hpp,给出GameEngine.o
编译每个游戏状态,例如用GameState.hpp编译TestState.cpp/hpp,得到TestState.o
使用GameEngine.o/hpp、GameState.hpp、TestState.o/hpp(以及任何其他状态)编译TestGame.cpp/hpp,可获得TestGame.bin
我走对了吗?GameEngine应该构建一个lib,还是一个常规的.o?我仍然有点不清楚是否需要在每次编译中包含头。此外,每次编译的输出文件是在与源文件相同的目录中,还是应该在结构化的bin/目录中?
我会玩一玩,发布一些Makefile尝试和输出。如果我应该发布代码,请告诉我,总共可能有200行。没有实际的图形实现等等…目前只是一个框架。
谢谢大家,非常感谢你们的帮助!
编辑:感谢大家的快速回复。我已经阅读了下面的评论,想更新并澄清一些事情。
首先,我正在研究自动工具,但这在很大程度上是一个学习项目,其中一部分是开发makefile。此外,我有Java背景,所以我真的很想确切地了解我正在构建什么,以及我的项目是如何组合在一起的。如上所述,我甚至不知道某个东西应该是一个库,还是只是在编译时指向它。
我的目标概述:我认为引擎几乎是一个子项目。即使它很简单(<10个文件),它也会加载我认为的"状态",并循环状态定义的[处理事件、更新、显示]方法。我有一种算法,它的目标是每秒更新次数恒定,同时根据需要改变帧速率。
例如,statesdisplay方法将使用引擎的SDL支持的显示功能(可能是平铺引擎,状态可以说"加载这些资源,显示这些平铺",或者小部件库,等等)来呈现游戏世界模型的表示。handle events方法可以使用抽象的键盘接口。我希望能够在引擎中添加这样的功能。更新将管理一个代表游戏世界的模型。它将跟踪世界上的物体(场景、玩家和np),应用基于物理的运动和碰撞检测等
我想我想能够构建这个,并在我正在开发的游戏中包含对象(和标题?)。这是否是一个问题'将引擎源目录复制到游戏项目的根目录,并将其添加到主Makefile中,一起构建',或者"每当引擎发生变化时,都在引擎上运行make,用最新引擎对象(共享对象,其他什么?)的副本和标题构建游戏项目",对我来说,使用一个引擎处理多个小型游戏项目最容易的是什么?我有点想让自己做好准备,这样我就可以用我所拥有的随机游戏创意,比如2周的编码comps,等等,脚踏实地
状态表示任何不同的视图和交互集。引擎有一个LIFO状态堆栈,因此一个简单的游戏可以在堆栈上有以下状态:行驶模式-暂停菜单-设置实际的游戏有一个GameEngine的实例,并且会添加DrivingMode来启动游戏。用户暂停,这将暂停DrivingMode状态并推送PauseMenu状态(在推送时运行其init、run等)。在这里,用户选择暂停暂停菜单状态的设置,并加载设置。。。当它们退出时,会弹出状态(清理等……首先运行),然后恢复顶部状态。
哇,现在太多了。随着我的进步,我会添加更多问题或提出新问题。再次感谢您的帮助。
首先,您真的需要状态是模块化的吗?如果您计划为特定目的编写引擎,那么您的状态可能不会有太大变化,因此可能应该作为引擎本身的一部分进行编译。
将状态与引擎分离会增加额外的复杂性,并使实现更加棘手。
下一个问题是,你是否希望你的引擎是一个游戏链接的库,或者引擎的源代码是否被放在游戏的子文件夹中,并与之一起编译。
您的选择是:
- 将引擎和状态编译为一个库(也许是一个静态库,用于链接游戏)
- 将引擎编译为静态库,然后将状态编译为可以动态链接的共享对象(这符合模块化状态选项,但会增加很多复杂性)
- 将整个引擎+游戏编译成一个大的可执行文件,这样就不需要任何库链接(但也使引擎和游戏更加耦合)
在我看来,选项1看起来是最好的
无论哪种选择,我都会将引擎保存在游戏中自己的子目录中。到目前为止,你的文件结构看起来相当稳固,你应该坚持下去
如果你仍然选择允许游戏定义自己的状态,那么你会想选择选项二,在你的引擎中实现一些核心状态(可能是INIT、MAIN_MENU、SHUT_DOWN)以及"插件管理器",在这种情况下,插件管理器将负责向游戏引擎注册游戏的状态。
然后,每个状态都可以单独编译为共享对象(.so),并在加载游戏时动态加载。
至于Makefiles,它实际上取决于你计划使用什么(CMake、GNU自动工具等)
GNU Makefile有一个非常简单的语法,但要想很好地使用它们可能有点棘手。
它们由如下定义的目标组成:
default:
gcc [...]
all:
gcc [...]
gcc [...]
<...>
当在没有参数的情况下调用make时,第一个目标是默认目标我不会详细描述如何使用makefiles(对于GNUMake:此链接)
您应该知道,makefile很快就会变得非常乏味,而像autotools这样的解决方案通常是首选。
请注意,自动工具是一个由许多程序组成的非常大的系统,学习起来可能非常耗时。如果你想专注于开发你的游戏引擎,我强烈建议你使用像Code::block这样的项目IDE来为你编译和链接代码。
编辑
作为对您编辑的回应,我将添加以下内容:
你似乎非常清楚自己要去哪里,这是最重要的部分。从你所说的来看,如果游戏引擎是你的许多游戏所链接的静态库,你会更好。
然后,你的引擎会提供一个界面来注册状态,游戏会用它来说"这是我的状态,名为title",然后在需要时告诉引擎"切换到名为title的状态"。
你可能想考虑的一件事是,所有游戏都必须注册一些基本状态(由引擎本身强制执行)。
然后引擎将是一个自己的项目,例如,游戏项目将在/lib中有一个引擎库的副本。然后,您将在编译时静态地将引擎链接到您的游戏。
如果你想了解更多关于如何构建状态对象的细节,请告诉我。
你问的很多事情都没有明确的答案——通常是个人偏好。
我从你的问题中得到的印象是,你也编译你的头,你不应该编译头,它们应该只包含在.cpp文件和其他头中。然后将它们作为cpp的一部分进行编译。文件应该只包含它们真正需要的标题。
只要你的项目很小,把所有东西都放在一个目录里通常是最好的,但如果你知道它会增长,那么建立一个好的目录结构是个好主意。像你一样,将潜在的可重复使用的游戏引擎与实际游戏分离是一件好事。
当该部分将在其他项目中重复使用时,或者当您的项目变得太大以至于.o文件的数量变得非常多时,创建库是有用的。因此,如果这适用于游戏引擎,请将其作为一个库。对于像游戏引擎这样的可重用项目,将标题保存在单独的目录中通常也很有用。因为依赖它的项目只需要头和lib,所以它们不需要其余的源。
当项目变得更大时,使用单独的源目录,intermediate(.o)和最终可执行文件有助于保持文件的可管理性,因为使用源存储.o通常会使src目录中的文件数量增加50%。
如果你想把它设置得很好,你可能想看看autoconf和automake。他们有一个陡峭的学习曲线,但他们会从你手中夺走很多Makefile的写作。这些是创建配置脚本的工具,在许多开源软件包的源代码发行版中都可以找到。
- 提高基于组件的游戏引擎的效率
- 虚幻引擎 3 游戏在 Steam 输入时崩溃
- 我的游戏引擎的 spdlog 日志记录出现奇怪的"unresolved external symbol"错误
- 游戏引擎矩阵乘法
- 如何在没有现有引擎的情况下在游戏中设计我的事件触发器框架?
- 游戏引擎 SFML C++错误
- 游戏引擎设计问题
- 使用虚幻引擎4编程的平台游戏中的偏转问题
- 我正在尝试安装游戏引擎,但遇到错误
- 我的游戏引擎的 FMOD 音频
- 如何在 GLFW 中为游戏引擎执行正确的输入类
- 游戏引擎:如何从结构:编码实践转换变量
- 如何防止游戏引擎更新循环中的多个声音呼叫
- 游戏引擎:Dynamic_cast-对象类不是多态类型
- 在游戏引擎布局中使用shared_ptr
- 虚幻引擎4.20在我尝试玩游戏时崩溃
- 如何打包游戏的资产并仅允许引擎读取
- C#或C++来制作游戏引擎(深度)
- DirectX 11 2D游戏引擎使用Direct 3D(C )
- 游戏中图形和物理引擎之间共享数据