我有一些简单的box2d机构设置与一个联系人监听器,如下所示: #import "MyContactListener.h"MyContactListener::MyContactListener() : _contacts() {}MyContactListener::~MyContactListener() {}void MyContactListener::BeginCon
#import "MyContactListener.h" MyContactListener::MyContactListener() : _contacts() { } MyContactListener::~MyContactListener() { } void MyContactListener::BeginContact(b2Contact* contact) { // We need to copy out the data because the b2Contact passed in // is reused. MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; _contacts.push_back(myContact); b2Body *A = contact->GetFixtureA()->GetBody(); b2Body *B = contact->GetFixtureA()->GetBody(); NSLog(@"Collision detected!"); PLAYSOUND(COLLISION); } void MyContactListener::EndContact(b2Contact* contact) { MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; std::vector<MyContact>::iterator pos; pos = std::find(_contacts.begin(), _contacts.end(), myContact); if (pos != _contacts.end()) { _contacts.erase(pos); } } void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { } void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { }
当两具尸体发生碰撞时,我需要发出声音.然而,该实现检测到连续碰撞,因此当身体接触时播放声音.我对box2d和C的了解已经非常有限,有没有一种简单的方法来检测新的碰撞而不会检测到连续的碰撞?
你有正确的基本想法,但它需要一些改进.在您的BeginContact(…)调用中,您有:
PLAYSOUND(COLLISION);
你应该做的不是在这里播放声音,而是将一些其他系统排入队列以播放这一特定对的声音.将您的body的userdata标记设置为指向该类的指针(或一些其他ID以跟踪实体).像这样:
class EntityContactListener : public ContactListener { private: GameWorld* _gameWorld; EntityContactListener() {} typedef struct { Entity* entA; Entity* entB; } CONTACT_PAIR_T; vector<CONTACT_PAIR_T> _contactPairs; public: virtual ~EntityContactListener() {} EntityContactListener(GameWorld* gameWorld) : _gameWorld(gameWorld) { _contactPairs.reserve(128); } void NotifyCollisions() { Message* msg; MessageManager& mm = GameManager::Instance().GetMessageMgr(); for(uint32 idx = 0; idx < _contactPairs.size(); idx++) { Entity* entA = _contactPairs[idx].entA; Entity* entB = _contactPairs[idx].entB; //DebugLogCPP("Contact Notification %s<->%s",entA->ToString().c_str(),entB->ToString().c_str()); msg = mm.CreateMessage(); msg->Init(entA->GetID(), entB->GetID(), Message::MESSAGE_COLLISION); mm.EnqueueMessge(msg, 0); msg = mm.CreateMessage(); msg->Init(entB->GetID(), entA->GetID(), Message::MESSAGE_COLLISION); mm.EnqueueMessge(msg, 0); } _contactPairs.clear(); } void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { } // BEWARE: You may get multiple calls for the same event. void BeginContact(b2Contact* contact) { Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData(); Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData(); //DebugLogCPP("Begin Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str()); if(entA->GetGroupID() == entB->GetGroupID()) { // Can't collide if they are in the same group. return; } assert(entA != NULL); assert(entB != NULL); for(uint32 idx = 0; idx < _contactPairs.size(); idx++) { if(_contactPairs[idx].entA == entA && _contactPairs[idx].entB == entB) return; // Not sure if this is needed... if(_contactPairs[idx].entA == entB && _contactPairs[idx].entA == entB) return; } CONTACT_PAIR_T pair; pair.entA = entA; pair.entB = entB; _contactPairs.push_back(pair); } // BEWARE: You may get multiple calls for the same event. void EndContact(b2Contact* contact) { /* Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData(); Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData(); DebugLogCPP("End Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str()); */ } };
最后一部分是即使发生碰撞也不会在短时间内再次播放声音.您可以通过创建秒表或从实体更新周期的固定时间倒计时来完成此操作.
这个有帮助吗?