Wie kann man mithilfe der Geschossphysik einen Kollisionsrückruf von zwei bestimmten Objekten erhalten?


7

Ich habe Probleme beim Implementieren des Kollisionsrückrufs in mein Projekt. Ich möchte eine Erkennung zwischen zwei bestimmten Objekten haben. Ich habe eine normale Kollision, aber ich möchte, dass ein Objekt stoppt oder seine Farbe ändert oder was auch immer, wenn es mit einem anderen kollidiert. Ich habe Code aus dem Bullet-Wiki geschrieben:

int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
    for (int i=0;i<numManifolds;i++)
    {
        btPersistentManifold* contactManifold =  dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
        btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
        btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());

        int numContacts = contactManifold->getNumContacts();
        for (int j=0;j<numContacts;j++)
        {
            btManifoldPoint& pt = contactManifold->getContactPoint(j);
            if (pt.getDistance()<0.f)
            {
                const btVector3& ptA = pt.getPositionWorldOnA();
                const btVector3& ptB = pt.getPositionWorldOnB();
                const btVector3& normalOnB = pt.m_normalWorldOnB;
                bool x = (ContactProcessedCallback)(pt,fallRigidBody,earthRigidBody);
                if(x)
                    printf("collision\n");
            }
        }
    }

Dabei ist fallRigidBody ein dynamischer Körper - eine Kugel und earthRigiBody ist ein statischer Körper - StaticPlaneShape und Kugel berühren earthRigidBody nicht ständig. Ich habe auch andere Objekte, die mit der Kugel kollidieren und es funktioniert gut. Das Programm erkennt jedoch ständig Kollisionen. Es spielt keine Rolle, ob die Objekte kollidieren oder nicht.

Ich habe auch nach Erklärungen des starren Körpers hinzugefügt:

    earthRigidBody->setCollisionFlags(earthRigidBody->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
fallRigidBody->setCollisionFlags(fallRigidBody->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);

Kann mir jemand sagen, was ich falsch mache? Vielleicht ist es etwas Einfaches?


Antworten:


3

Ich bin mit JBullet vertraut, aber da es der Java-Port des Originals ist, sollte das Konzept dasselbe sein.

Es schien mir, dass es immer eine Kollision mit Ihrer statischen Ebene und anderen Objekten gibt. Sie müssen jedoch nur bei einer Kollision bestimmter Objekte etwas tun. Was Sie verwenden müssen, ist der Benutzerzeiger der Kollisionsform. Hier ist ein Stück Code von meiner eigenen Engine in Java. Hier ist GameEntity die Klasse, in die ich meine Objekte einpacke, und CollisionListener ist eine weitere Klasse von mir, mit der ich implementiere, was Kollisionen bewirken. Ich übergebe dem Hörer auch normale Positionen und Kollisionen, um ausgefallenere Effekte zu erzielen.

            if (pt.getDistance() < 0.f) {
                Vector3f ptA = pt.getPositionWorldOnA(new Vector3f());
                Vector3f ptB = pt.getPositionWorldOnB(new Vector3f());
                Vector3f normalOnB = pt.normalWorldOnB;
                GameEntity thisObject = (GameEntity) (obA.getUserPointer());
                GameEntity thatObject = (GameEntity) (obB.getUserPointer());
                if(thisObject == null){
                    return;
                }
                if (thisObject.getCollisionListener() != null) {
                    thisObject.getCollisionListener().collided(
                            ptA, ptB, normalOnB, thatObject);
                }
                if (thatObject.getCollisionListener() != null) {
                    thatObject.getCollisionListener().collided(
                            ptB, ptA, normalOnB, thisObject);
                }
            }

0

Minimal lauffähiges Beispiel

Zwei Kugeln, die in Abhängigkeit von der Zeit aus unterschiedlichen Höhen fallen.

Da sie in unterschiedlichen Höhen beginnen, werden sie zu unterschiedlichen Zeiten auf dem Boden aufschlagen.

Wir erkennen den Bodentreffer und drucken aus, welche Kugel wann den Boden berührt hat.

Gnuplot-Visualisierung von stdout:

Siehe wie:

  • Wenn eine Kugel auf den Boden trifft, geht die Kollisionsanzeige mit dem rosa Quadrat zu 1
  • Wenn die andere Kugel auf den Boden trifft, Xgeht das Grün zu1

Code:

#include <cstdio>
#include <cstdlib>
#include <map>
#include <vector>

#include <btBulletDynamicsCommon.h>

#define PRINTF_FLOAT "%7.3f"

constexpr float gravity = -10.0f;
constexpr float timeStep = 1.0f / 60.0f;
constexpr float groundRestitution = 0.9f;
constexpr float objectRestitution = 0.9f;
constexpr int maxNPoints = 500;
constexpr float initialXs[] = {  0.0f, 5.0f };
constexpr float initialYs[] = { 10.0f, 5.0f };
constexpr size_t nObjects = sizeof(initialYs) / sizeof(*initialYs);

std::map<const btCollisionObject*,std::vector<btManifoldPoint*>> objectsCollisions;
void myTickCallback(btDynamicsWorld *dynamicsWorld, btScalar timeStep) {
    objectsCollisions.clear();
    int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
    for (int i = 0; i < numManifolds; i++) {
        btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
        auto *objA = contactManifold->getBody0();
        auto *objB = contactManifold->getBody1();
        auto& collisionsA = objectsCollisions[objA];
        auto& collisionsB = objectsCollisions[objB];
        int numContacts = contactManifold->getNumContacts();
        for (int j = 0; j < numContacts; j++) {
            btManifoldPoint& pt = contactManifold->getContactPoint(j);
            collisionsA.push_back(&pt);
            collisionsB.push_back(&pt);
        }
    }
}

int main() {
    int i, j;

    btDefaultCollisionConfiguration *collisionConfiguration
            = new btDefaultCollisionConfiguration();
    btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);
    btBroadphaseInterface *overlappingPairCache = new btDbvtBroadphase();
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
    btDiscreteDynamicsWorld *dynamicsWorld = new btDiscreteDynamicsWorld(
            dispatcher, overlappingPairCache, solver, collisionConfiguration);
    dynamicsWorld->setGravity(btVector3(0, gravity, 0));
    dynamicsWorld->setInternalTickCallback(myTickCallback);
    btAlignedObjectArray<btCollisionShape*> collisionShapes;

    // Ground.
    {
        btTransform groundTransform;
        groundTransform.setIdentity();
        groundTransform.setOrigin(btVector3(0, 0, 0));
        btCollisionShape* groundShape;
        groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), -1);
        collisionShapes.push_back(groundShape);
        btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
        btRigidBody::btRigidBodyConstructionInfo rbInfo(0, myMotionState, groundShape, btVector3(0, 0, 0));
        btRigidBody* body = new btRigidBody(rbInfo);
        body->setRestitution(groundRestitution);
        dynamicsWorld->addRigidBody(body);
    }

    // Objects.
    for (size_t i = 0; i < nObjects; ++i) {
        btCollisionShape *colShape;
        colShape = new btSphereShape(btScalar(1.0));
        collisionShapes.push_back(colShape);
        btTransform startTransform;
        startTransform.setIdentity();
        startTransform.setOrigin(btVector3(initialXs[i], initialYs[i], 0));
        btVector3 localInertia(0, 0, 0);
        btScalar mass(1.0f);
        colShape->calculateLocalInertia(mass, localInertia);
        btDefaultMotionState *myMotionState = new btDefaultMotionState(startTransform);
        btRigidBody *body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
                mass, myMotionState, colShape, localInertia));
        body->setRestitution(objectRestitution);
        dynamicsWorld->addRigidBody(body);
    }

    // Main loop.
    std::printf("step body x y z collision2 collision1\n");
    for (i = 0; i < maxNPoints; ++i) {
        dynamicsWorld->stepSimulation(timeStep);
        for (j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; --j) {
            btCollisionObject *obj = dynamicsWorld->getCollisionObjectArray()[j];
            btRigidBody *body = btRigidBody::upcast(obj);
            btTransform trans;
            if (body && body->getMotionState()) {
                body->getMotionState()->getWorldTransform(trans);
            } else {
                trans = obj->getWorldTransform();
            }
            btVector3 origin = trans.getOrigin();
            std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
                    i, j, origin.getX(), origin.getY(), origin.getZ());
            auto& manifoldPoints = objectsCollisions[body];
            if (manifoldPoints.empty()) {
                std::printf("0");
            } else {
                std::printf("1");
            }
            puts("");
        }
    }

    // Cleanup.
    for (i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; --i) {
        btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i];
        btRigidBody* body = btRigidBody::upcast(obj);
        if (body && body->getMotionState()) {
            delete body->getMotionState();
        }
        dynamicsWorld->removeCollisionObject(obj);
        delete obj;
    }
    for (i = 0; i < collisionShapes.size(); ++i) {
        delete collisionShapes[i];
    }
    delete dynamicsWorld;
    delete solver;
    delete overlappingPairCache;
    delete dispatcher;
    delete collisionConfiguration;
    collisionShapes.clear();
}

Getestet auf Bullet 2.83, Ubuntu 15.10.

GitHub Upstream: https://github.com/cirosantilli/cpp-cheat/blob/d7b70153b8f86b5864c22fbc6f7005049a93491f/bullet/which_collision.cpp


@ Downvoters, bitte erklären Sie, damit ich lernen und mich verbessern kann ;-)
Ciro Santilli 26 病毒 审查 六四 事件 26
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.