简体   繁体   English

重构:使游戏引擎更加模块化以及如何实现

[英]Refactoring: Making a game engine more modular and how

My game engine consists of a range of loosely coupled modules, which can be loaded and unloaded. 我的游戏引擎由一系列松散耦合的模块组成,可以加载和卸载。

Some examples are: The base module, handling window management and responding to OS events, entity manager, Lua manager, physics manager. 一些示例是:基本模块,处理窗口管理和响应OS事件,实体管理器,Lua管理器,物理管理器。

Right now, these modules are organized as namespaces, and their state is defined through local variables in the respective source files. 现在,这些模块被组织为命名空间,它们的状态通过相应源文件中的局部变量来定义。 Each of the namespaces has an Open(), Close() and Update() function. 每个命名空间都有一个Open(),Close()和Update()函数。

Now, I don't really like the solution with namespaces anymore. 现在,我真的不喜欢名称空间的解决方案了。

  • It's not flexible enough 它不够灵活

  • Even if it might not be needed in reality, having the plain ability of creating multiple instances of a module seems proper 即使在现实中可能不需要它,具有创建模块的多个实例的简单能力似乎是正确的

  • It seems like I'm not making use of OOP here - a module base class with a virtual Update() member function would sound more reasonable 好像我在这里没有使用OOP - 一个带有虚拟Update()成员函数的模块基类听起来更合理

  • It's harder to ensure that when the module is closed and reopened, all of the variables will be reset too (A class with constructors and destructors would be easier) 当模块关闭并重新打开时,更难以确保所有变量也将被重置(具有构造函数和析构函数的类将更容易)

  • You can't properly have the modules managed without explicitly calling Open(), Close() and Update() 如果没有显式调用Open(),Close()和Update(),就无法正确管理模块

So, my idea would have been to use classes for each of the modules, derived from a module base class. 所以,我的想法会一直使用为每个模块,从模块基类派生。 The module class instances would be handled by the ModuleManager class, which updates them. 模块类实例将由ModuleManager类处理,后者会更新它们。

But the solution with OOP brings up the problem of how the modules should communicate. 但是OOP的解决方案带来了模块应该如何通信的问题。 Right now, the base module told the console module to print something via console::print() 现在,基础模块告诉控制台模块通过console::print()打印一些东西

  • How can I work around this problem without having to use something like g_ModuleManager.GetConsoleModule()->print() ? 如何解决这个问题而不必使用像g_ModuleManager.GetConsoleModule()->print()

  • How could this module manager work in detail? 这个模块管理器怎么能详细工作?

And my final question: 我的最后一个问题是:

  • Do you have any further tips for me on the topic of writing a modular game engine in C++ with OOP? 对于使用OOP用C ++编写模块化游戏引擎这个主题,你有什么进一步的提示吗?

  • Are there any design patterns that could help me in this situation, or maybe even concrete reading material? 是否有任何设计模式可以帮助我在这种情况下,甚至可能是具体的阅读材料?

Namespaces become very inflexible very quickly. 命名空间很快变得非常灵活。
One way to keep things loosely coupled is to use messaging through a central message dispatcher; 保持松散耦合的一种方法是通过中央消息调度程序使用消息传递; rather than saying console::print you would say messenger->sendMessage(PRINT_MESSAGE, stuffToPrint) . 而不是说console::print你会说messenger->sendMessage(PRINT_MESSAGE, stuffToPrint)
The console would register itself as a listener to PRINT_MESSAGE s and act the way it wants to. 控制台会将自己注册为PRINT_MESSAGE的监听器,并以其想要的方式运行。 The sender doesn't need to care whether someone's listening, and there could even be several listeners to each message (useful for debugging). 发送者不需要关心某人是否在监听,每个消息甚至可能有几个监听器(对调试很有用)。

Regarding reading materials, Jason Gregory's "Game Engine Architecture" is pretty good, discussing the pros and cons of several architectures. 关于阅读材料,杰森格雷戈里的“游戏引擎架构”非常好,讨论了几种架构的优缺点。

First as a general reminder, just remember to use inheritance for substitutability, not code reuse. 首先作为一般提醒,只记得使用继承来代替可替代性,而不是代码重用。 Roughly this means that anything that inherits from your base module needs to support (mostly) the same operations, and that if a user says open , close , or update on any module, it will provide expected results. 粗略地说,这意味着从您的基础模块继承的任何东西都需要支持(大部分)相同的操作,并且如果用户说任何模块上的opencloseupdate ,它将提供预期的结果。

Do you really want a module manager? 你真的想要一个模块经理吗? It might be better instead to draw a diagram of the relationships between your different classes/modules and create the linkage there rather than a top-level manager. 可能更好的是绘制不同类/模块之间关系的图表,并在那里创建链接而不是顶级经理。 Then the application's main loop would know about one or more high level modules and call the appropriate methods on them directly. 然后应用程序的主循环将知道一个或多个高级模块并直接调用它们上的相应方法。 If desired there could even be a high-level module to manage this high level of delegation. 如果需要,甚至可以有一个高级模块来管理这种高级别的授权。

For your console example, assuming you don't want to support multiple consoles, you're probably better off just keeping the namespace: It gives you the ability to directly refer to the single console that you're interfacing with. 对于您的控制台示例,假设您不想支持多个控制台,您可能最好只保留命名空间:它使您能够直接引用您正在连接的单个控制台。 Alternately you could require a "parent console" be passed in to each module that's created and it uses that associated console to do its I/O as appropriate. 或者,您可以要求将“父控制台”传递给创建的每个模块,并使用该关联控制台根据需要执行其I / O. This gives you rather more flexibility at the expense of needing to make sure that you have to maintain the console within your base module. 这为您提供了更大的灵活性,但需要确保您必须在基础模块中维护控制台。

g_ModuleManager.GetConsoleModule()->print()

simple, as stated before me, you are most likely going to have to refactor a lot of things to take advantage of OOP. 很简单,如前所述,你很可能不得不重构很多东西来利用OOP。 You want each class to have a distinctive relationship, not all managed on an equal playing field. 你希望每个班级都有一个独特的关系,而不是所有人都在平等的竞争环境中进行管理。 Whoever is telling the the ConsoleModule to print should have its own print function that tell the ConsoleModule to print. 告诉ConsoleModule要打印的人应该有自己的打印功能,告诉ConsoleModule打印。 This way you just say print() 这样你就说print()

also think in term of "has a" for composition and "is a" for inheritance. 也认为在“有一个”的组成和“是一个”的继承。 I would read the entire section 8: http://www.learncpp.com/cpp-tutorial/81-welcome-to-object-oriented-programming/ 我会阅读整个第8节: http//www.learncpp.com/cpp-tutorial/81-welcome-to-object-oriented-programming/

As an example my current project: I have a board that "has" beatles , walls , and apples . 作为我当前项目的一个例子:我有一块“有” beatleswallsapples的板子。 Each of those "is an" icon 每个“都是” icon

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM