草庐IT

c++ - 物理引擎的继承/接口(interface)决策

coder 2024-02-02 原文

这是针对在 MinGW/Windows 上使用 SDL 的小型游戏项目。

我正在研究一个物理引擎,我的想法是拥有一个Physics::Object,所有物理对象都应该派生自它,并且它会在全局 Physics::中注册自己System 类(这是一个单态模式),因此用户不需要跟踪哪些对象包含在物理计算中,只需要调用一个函数,如 Physics::System::PerformTimestepCalculation(double dt )

这很好用,我什至使用一个派生类 Physics::Circle 实现它,这是一个二维圆。我对预测碰撞检测非常满意,尽管我仍然需要对其进行优化。

无论如何,当我开始添加其他原语以包含在计算中时,我遇到了麻烦,例如线。 Physics::System::PerformTimestepCalculation(double dt) 充斥着对 Object::GetID() 或类似函数的调用(可能是避免 dynamic_cast<> 的方法),但我觉得很脏。

我做了一点 reading并意识到我的层次结构的元素是不可替代的(即两个圆圈之间的碰撞与两条线的碰撞之间有很大不同)。

我喜欢我的 Physics::ObjectsSystem 类“ self 注册”的方式,因此它们会自动包含在计算中,我真的不想失去这个。

必须有一些其他合理的设计路径。我怎样才能更好地重新设计事物,使不可替代的对象不会挡路?

编辑仅供引用: 最后,我打破了实体和形状属性,类似于接受的答案中的描述,类似于实体组件系统模型。这意味着我仍然有“这是圆还是线,那是线还是圆?”的逻辑,但我不再假装多态性在这里帮助了我。这也意味着我使用某种工厂并且可以同时发生多个计算世界!

最佳答案

最成功的公开可用物理引擎在“模式”或“面向对象设计”方面并不是很重要。

以下是支持我公认的大胆断言的摘要:

Chipmunk - 用 C 语言编写,说的够多了。

Box2d - 用 C++ 编写,这里有一些多态性。有一个带有一些虚函数的形状层次结构(基类 b2Shape)。但是,这种抽象像筛子一样漏水,您会在整个源代码中发现许多对叶类的转换。还有一个“联系人”层次结构,它被证明更成功,尽管使用单个虚函数在没有多态性的情况下重写它是微不足道的(我相信花栗鼠使用函数指针)。 b2Body是用来表示刚体的类,它是非虚拟的。

Bullet - 用 C++ 编写,用于大量游戏。大量的功能,大量的代码(相对于其他两个)。实际上有一个刚体和软体表示扩展的基类,但只有一小部分代码可以使用它。基类的大部分虚函数与序列化(引擎状态的保存/加载)有关,软体无法实现剩余的两个虚函数,其中一个带有 TODO 通知我们需要清理一些 hack。不完全是对物理引擎中多态性的响亮认可。

说了很多,我什至还没有真正开始回答你的问题。我想强调的是,多态性并不是现有物理引擎中有效应用的东西。这可能不是因为作者没有“理解”面向对象。

所以无论如何,我的建议是:为您的实体类放弃多态性。你最终不会得到 100 种以后不可能重构的不同类型,你的物理引擎的形状数据将相当均匀(凸多边形、长方体、球体等),你的实体数据可能是甚至更均匀(一开始可能只是刚体)。

我认为您犯的另一个错误是只支持一个 Physics::System。能够独立地模拟彼此的 body (例如,对于两人游戏)是有用的,最简单的方法是支持多个 Physics::Systems。

考虑到这一点,要遵循的最干净的“模式”就是工厂模式。当用户想要创建一个刚体时,他们需要告诉 Physics::System(充当工厂)为他们做这件事,所以在你的 Physics::System 中:

// returning a smart pointer would not be unreasonable, but I'm returning a raw pointer for simplicity:
rigid_body_t* AddBody( body_params_t const& body_params );

在客户端代码中:

circle_params_t circle(1.f /*radius*/);
body_params_t b( 1.f /*mass*/, &circle /*shape params*/, xform /*system transform*/ );
rigid_body_t* body = physics_system.AddBody( b );

无论如何,有点咆哮。希望这会有所帮助。至少我想向您指出 box2d。它是用一种非常简单的 C++ 方言编写的,其中应用的模式将与您的引擎相关,无论是 3D 还是 2D。

关于c++ - 物理引擎的继承/接口(interface)决策,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9339129/

有关c++ - 物理引擎的继承/接口(interface)决策的更多相关文章

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

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

  2. 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

  3. ruby-on-rails - Rails 中的推荐引擎 - 2

    我想为我的Rails网络应用程序提供推荐功能。特别是,我想向新注册的用户推荐他可能想要关注的其他用户。Rails中是否有用于此目的的引擎/gem?如果没有,我应该从哪里开始构建它?谢谢。 最佳答案 有Coletivogemhttps://github.com/diogenes/coletivo我试了一下。在MySQL上运行。Neo4jhttp://neo4j.org真的很容易实现一个“跟随谁”。事实上,大多数展示其能力的样本都涉及“跟随谁”。快速提示-只有在JRuby上运行时,Neo4j.rb才会很酷。如果不是-使用Neograph

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  8. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  9. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐