2个物体之间的子弹碰撞回调

Posted

技术标签:

【中文标题】2个物体之间的子弹碰撞回调【英文标题】:bullet collision callback between 2 bodies 【发布时间】:2013-12-16 12:39:04 【问题描述】:

我有 2 个对象,一个球体和一个盒子,当其中一个与另一个碰撞时,它们会做一些动作(即摧毁盒子)。

我尝试了几种方法:

checkCollideWith 总是返回 true; contactPairTest - 这个我不明白怎么用。 它需要 3 个参数、2 个对象和一个回调。我以为回调可以是我代码中的任何函数,但它不是那样工作的。

谁能举例说明当 2 个 btRigidBodies 碰撞(即 bodyA 和 bodyB)时如何调用方法,例如 CollissionResult()?

【问题讨论】:

对文档的快速检查表明,contactPairTest 需要一个类型派生自抽象类 ContactResultCallback 的对象。所以你的问题是如何做到这一点? 【参考方案1】:

也许这个例子将有助于解释这个概念。您必须定义一个从现有抽象类派生的新类。您使用回调代码覆盖抽象类方法之一。然后创建派生类的对象并将其传递给要调用回调的函数。这是一种足够常见的 C++ 技术。

struct MyContactResultCallback : public ContactResultCallback

    btScalar addSingleResult(btManifoldPoint& cp,
        const btCollisionObjectWrapper* colObj0Wrap,
        int partId0,
        int index0,
        const btCollisionObjectWrapper* colObj1Wrap,
        int partId1,
        in index1)
    
        // your callback code here
    
;

MyContactResultCallback callback;
world.contactPairTest(bodyA, bodyB, callback);

我应该补充一点,我对这个库一无所知。我刚刚阅读了文档。

编辑

展示如何将上下文成员添加到MyContactResultCallback

struct MyContactResultCallback : public ContactResultCallback

    MyContactResultCallback(some_type* ptr) : context(ptr) 

    btScalar addSingleResult(btManifoldPoint& cp,
        const btCollisionObjectWrapper* colObj0Wrap,
        int partId0,
        int index0,
        const btCollisionObjectWrapper* colObj1Wrap,
        int partId1,
        in index1)
    
        context->currentPoints += 10;
    

    some_type* context;
;

MyContactResultCallback callback(ptr_to_some_object);
world.contactPairTest(bodyA, bodyB, callback);

ptr_to_some_object 是指向您要递增的具有currentPoints 的对象的指针。我不知道那是什么类型的对象,所以我刚才说some_type,你可以用任何真正的类型替换它。

这是使用对象作为回调而不是函数的要点。如果回调是一个对象,您可以将数据成员添加到您想要的任何目的,您不能对函数执行此操作。

【讨论】:

你好。谢谢回复。我已经尝试了您的示例,然后创建了一个 myContactResultCallback 对象MyContactResultCallback callback;,然后调用了contactPairTest 方法bt_dynamicsWorld->contactPairTest(bodyA, bodyB, callback);。运行导致报错说addSingleResult需要返回一个值,所以我加了return 0;。这允许程序运行,但是当我碰撞 2 个对象时,没有调用回调(2 个对象显然在反弹时碰撞) @b0Gd4N 好吧,恐怕我已经尽可能地帮助了你(即使用 C++ 语法)。正如我所说,我根本不知道这个库。 它不起作用的原因是我忘记将collisionFlags 添加到两个对象中。所以现在我有 2 个对象碰撞并调用回调,但是我遇到了另一个问题:在评论 // your callback code here 之后,我有一个报告碰撞的输出,它可以工作。在此之后,我想增加一个在头文件中声明为公共的变量,因此它应该可以在任何地方访问。但是当我写currentPoints += 10 时,我收到一个错误a nonstatic member reference must be relative to a specific object。我怎样才能通过这个? @b0Gd4N 这就是将回调作为对象的美妙之处。添加指向MyContactResultCallback 结构的指针。指针指向具有要递增的变量的对象。然后您可以使用该指针从MyContactResultCallback::addSingleResult 内部执行增量 我一直在努力制作这个指针一段时间。我尝试向 addSingleResult 方法添加另一个参数,但是当我创建结构的实例时,我收到错误 addSingleResult is not overridable。我真的不明白我必须按照你说的去做。【参考方案2】:

我发现最简单的方法是检查歧管。如果您只询问dispatcher,则无需自定义类。

每次踏入世界后都执行这个:

    btDispatcher* dp = world->getDispatcher();
    const int numManifolds = dp->getNumManifolds();
    for ( int m=0; m<numManifolds; ++m )
    
            btPersistentManifold* man = dp->getManifoldByIndexInternal( m );
            const btRigidBody* obA = static_cast<const btRigidBody*>(man->getBody0());
            const btRigidBody* obB = static_cast<const btRigidBody*>(man->getBody1());
            const void* ptrA = obA->getUserPointer();
            const void* ptrB = obB->getUserPointer();
            // use user pointers to determine if objects are eligible for destruction.
            ...
            const int numc = man->getNumContacts();
            float totalImpact = 0.0f;
            for ( int c=0; c<numc; ++c )
                    totalImpact += man->getContactPoint(c).m_appliedImpulse;
            if ( totalImpact > threshold )
            
                    // Here you can break one, or both shapes, if so desired.
            
    

【讨论】:

以上是关于2个物体之间的子弹碰撞回调的主要内容,如果未能解决你的问题,请参考以下文章

子弹物理引擎,如何冻结物体?

重新定义物体的碰撞箱?

unity碰撞检测(碰撞器,触发器)

unity3d碰撞器检测碰撞跟触发器检测碰撞哪个好些

无法在 box2d 碰撞回调中获取类数据

unity怎么用C#写子弹碰到物件3次才死