如何检查几何基类中的碰撞而不转换为派生类

Posted

技术标签:

【中文标题】如何检查几何基类中的碰撞而不转换为派生类【英文标题】:How to check collision in geometric base classes without casting to derived ones 【发布时间】:2014-09-08 09:37:10 【问题描述】:

我有这种情况:

 class Shape;
 class Triangle : public Shape;
 class Rectangle : public Shape;
 class Square : public Rectangle;

我想在以这种方式工作的基类中实现virtual collideWith 方法:

Shape *square = new Square();
Shape *triangle = new Triangle();

bool test = square.collideWith(triangle);

有没有办法实现这个方法,以便在不显式转换的情况下与基类一起使用派生类?

我想创建一个命名空间来做到这一点:

namespace Collision 
  bool isCollisionBetween(const Triangle &triangle, const Square &square) /* calculus */
  bool isCollisionBetween(const Rectangle &rect, const Square &square) /* calculus */
  // and so on for all combination

但是当我有类似的东西时,我不知道如何应用它

std::set<Shape*> shapesSet;

我想计算这个集合的所有碰撞。

是否有可能或总是需要将Shape 类显式转换为正确继承的类?

【问题讨论】:

我猜你应该创建另一个名为collisionInformation 的类,并把你可以比较的数据放在那里。而不是简单地比较返回的碰撞信息... 你说的是在基类中实现的一些枚举器,上面写着“我是一个圆圈”“我是一个超级复杂的形状,你永远不会在你的生活中看到”,在派生类中初始化这个成员值并用它来检查哪个 @ 987654328@我应该调用的函数? 【参考方案1】:

一般来说,你会这样解决一个问题:

    Shape 一个描述形状的抽象函数,每个子类都必须实现该函数。 每个子类都根据其具体类型实现此功能。 Shape 中的collideWith() 函数使用两种类型的抽象函数来确定属性。

这样,当添加一个形状时,不需要更改任何其他形状,并且您不必添加函数来将其与其他形状进行比较。只有新形状必须提供所有必需属性的功能。

现在困难的部分是决定每个形状可以提供什么属性。在您的情况下,可能很难为其提供有效的实现。

可用于提供碰撞检测的属性示例如下:

    polygonRepresentation() asVectorGrahpic() convertToBitMap()

您可以想象,在您的问题中,可能很难找到适合每个项目的适当表示。然后你可能不得不恢复到知道所有元素的比较。但这确实是一种反面向对象的模式,当形状或属性的数量增加时会带来麻烦。

【讨论】:

我知道它可能不是一个很好的 OO 模式,但是通过这种方式我可以执行特定的碰撞检测,它可以比通用的更快。我喜欢将所有形状转换为标准格式的想法,但这样我就不能使用比多边形的通用算法更快的特定碰撞算法(例如,我考虑圆-圆碰撞)。所以我不能加入专用碰撞检测算法和格式良好的 OO 模式中的基类通用性的世界? 最后,如果你想真正具体,你必须求助于知道类型。您可以使用多个抽象属性进行比较,虽然不理想,但它确实保留了抽象:isCicularShape() radius() 可以由所有人实现(其中radius() 将在非循环类型上返回无效,如果您给出'反OO'感觉马上)。然后,如果您的比较有两个圆形,则它使用半径,否则回退到默认实现。否则我担心你会退回到铸造。 好的,我会认为最适合我的问题的方法。感谢您的回复。【参考方案2】:

好的,我的评论有点误导你。我的意思是:

    要创建collisionInformation,请制作类似于“BroadPhase”的内容(这是可选的,但非常有用)。将其视为潜在形状是否发生碰撞的预检查。谷歌因此“二进制空间分区”。在这个时候忘记四叉树或八叉树。此阶段将创建一个潜在的联系人及其信息。问问你自己:哪些形状正在碰撞?我在调用哪个冲突解决函数?我应该使用多态还是函数指针? (即调用指向 static bool CollisionResolver::handle( Box b, Circle c ); 的函数指针,可以通过 collisoinInformation 检索/调用)。如果发生碰撞,我会调用什么回调?将所有这些信息保存到这个 collisoinInformation 对象 创建不同的碰撞句柄函数来处理不同形状之间的碰撞。迭代您的即std::vector 保存您的collisionInformation 并调用(现在虚构的函数)colIter-&gt;resolve(),它正在调用您的碰撞句柄函数的正确实现。如果你发现了冲突,问问自己:我会调用哪些函数?我可以提供什么信息?即将附加信息填充到您的collisoinInformation 中,或者创建一个新对象collisionPair 等...您可以保存碰撞点、法线、形状...... 碰撞检测成功,正在调用“已保存”回调到您的最终游戏对象。即你可以打电话给GameObject::OnCollision( const ContactPair&amp; p );

希望这比我之前添加的评论对您有所帮助 ps:给初学者的一个很好的提示:看看当前开源实现的幕后。即ODE或PhysX

【讨论】:

谢谢,这很有帮助。

以上是关于如何检查几何基类中的碰撞而不转换为派生类的主要内容,如果未能解决你的问题,请参考以下文章

C++ 类型将基础对象转换为派生对象

C++如何使用派生类构造函数销毁基类中的对象

c++继承是如何工作的?

访问派生类中的基类成员

虚函数和基类中的this指针的问题!

使用派生类中的基类方法 - 错误