当两个物体在 Bullet Physics 中碰撞时开始播放声音的好方法

Good way to start playing sound when two object collide in Bullet Physics

我正在尝试在我的引擎中实现碰撞的音频功能,但我很难找到一个好的方法来实现它。我使用 Bullet Physics,我想在两个物体碰撞时播放声音。我通过 gContactAddedCallback 实现了回调机制,所以每次两个对象发生碰撞时我都会得到回调。我遇到的问题是在每个游戏循环中可以多次调用回调函数,我不确定如何播放碰撞音频。

我想保留某种列表,其中包含某个对象的所有当前碰撞,但是通过这种方式,我再次不确定何时清理列表。我尝试在每个游戏循环中清理列表,但我仍然收到两个对象碰撞的多个回调。

任何人都可以解释或指向解释使物理引擎和音频协同工作的正确方法的资源吗?

好的,所以我找到了一种方法来完成我正在寻找的事情,但它似乎没有经过优化并且有点老套。我仍然想知道是否有一种我没有看到的简单方法可以做到这一点。这是我现在所做的。我保留了一个持续冲突列表,并将其与另一个当前冲突列表进行比较。如果当前碰撞有一个条目在持久碰撞列表中不存在,我将其添加到持久碰撞列表中并播放声音。之后,我遍历持久冲突列表并删除所有未包含在当前冲突列表中的条目。这是代码。

// persistentCollisions map.
std::map<int, std::vector<int>> persistentCollisions;

// Main game loop
while (!glfwWindowShouldClose(window.getWindow()))
{
    //.
    //.
    //.

    physicsEngine->getDynamicsWorld()->stepSimulation(1.0f / 60.0f);

    // New collision map
    std::map<int, std::vector<int>> newCollisions;

    // Go over the collision manifold and extract all existing collisions
    int numManifolds = physicsEngine->getDynamicsWorld()->getDispatcher()->getNumManifolds();
    for (int i = 0; i < numManifolds; i++)
    {
        btPersistentManifold* contactManifold = physicsEngine->getDynamicsWorld()->getDispatcher()->getManifoldByIndexInternal(i);
        const btCollisionObject* obA = contactManifold->getBody0();
        const btCollisionObject* obB = contactManifold->getBody1();

        int numContacts = contactManifold->getNumContacts();
        for (int j = 0; j < numContacts; j++)
        {
            btManifoldPoint& pt = contactManifold->getContactPoint(j);
            if (pt.getDistance() < 0.f)
            {
                // If it is a new collision, add to the newCollision list
                if (std::find(newCollisions[obA->getUserIndex()].begin(), newCollisions[obA->getUserIndex()].end(), obB->getUserIndex()) == newCollisions[obA->getUserIndex()].end()) 
                {
                    newCollisions[obA->getUserIndex()].emplace_back(obB->getUserIndex());
                }
            }
        }
    }


    // Iterate over new collisions and add new collision to persistent collisions if it does not exist
    std::map<int, std::vector<int>>::iterator newCollisionIterator = newCollisions.begin();
    while (newCollisionIterator != newCollisions.end())
    {
        for (auto item : newCollisionIterator->second)
        {
            if (std::find(persistentCollisions[newCollisionIterator->first].begin(), persistentCollisions[newCollisionIterator->first].end(), item) == persistentCollisions[newCollisionIterator->first].end()) 
            {
                std::cout << "New collision between " << newCollisionIterator->first << " And " << item << std::endl;
                // We can play our collision audio here
                persistentCollisions[newCollisionIterator->first].emplace_back(item);
            }
        }

        newCollisionIterator++;
    }

    // Iterate over persistent collisions and remove all collisions that did not exist in new collision
    std::map<int, std::vector<int>>::iterator persistentCollisionIterator = persistentCollisions.begin();
    while (persistentCollisionIterator != persistentCollisions.end())
    {
        std::vector<int>::iterator iter;
        for (iter = persistentCollisionIterator->second.begin(); iter != persistentCollisionIterator->second.end(); ) 
        {
            if (std::find(newCollisions[persistentCollisionIterator->first].begin(), newCollisions[persistentCollisionIterator->first].end(), *iter) != newCollisions[persistentCollisionIterator->first].end())
            {
                ++iter;
            }
            else
            {
                iter = persistentCollisionIterator->second.erase(iter);
            }
        }

        persistentCollisionIterator++;
    }
}