草庐IT

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

coder 2024-02-02 原文

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

有一个抽象类 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++ - 构建基于状态的游戏引擎和 Makefile 结构有帮助吗?的更多相关文章

    1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    5. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    6. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

      我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

    7. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

      只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

    8. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

      对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

    9. ruby - Net::HTTP 获取源代码和状态 - 2

      我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

    10. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

      给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

    随机推荐