我创建了火车。它是组合(联合)矩形,车轴,轮子。我想检测与其他身体(星星或水果)的碰撞矩形。
任何想法或建议都应该对我有很大帮助。
我最近对另一个问题给出了这个答案。我假设您正在使用 box2d 作为火车部件。
如果您使用的是 box2d,那么在处理世界更新时,碰撞检测将在 Box2d 引擎中处理。这会检测身体上的固定装置之间的碰撞,而不是身体本身。因此,如果您的身体由一组固定装置组成,您可以检测到身体的很小一部分(而不仅仅是边界矩形)。
简单的答案是从 b2ContactListener 派生一个类并告诉 b2World 你想使用它。手册中的示例如下所示:
class MyContactListener : public b2ContactListener
{
public:
void BeginContact(b2Contact* contact) { /* handle begin event */ }
void EndContact(b2Contact* contact) { /* handle end event */ }
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{ /* handle post-solve event */ }
};
您在派生类的实例上使用 b2World::SetContactListener(...) 注册它。
然而,事情并没有那么简单。我的经验是,对于一次“碰撞”,您会在世界更新期间接到多个班级电话。因此,如果在碰撞检测阶段碰撞破坏了一个对象,那么当其他事件在同一检测周期内发生时,您可能会遇到问题(死指针?)。
下面是一个更完整的解决方案。在这种情况下,世界上的每个“事物”都有一个 b2Body 并且用户标签指向根类(称为实体)。它会累积一个冲突列表并检查每个新事件是否引用了已经看到的一对,从而过滤掉重复项。在世界更新 NotifyCollisions 被调用以向实体发送消息,表明发生了碰撞并且他们需要对此做一些事情。
这是更大代码库的一部分;如果您需要澄清,请随时提出任何问题,因为代码不在这里。
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());
*/
}
};
这个有帮助吗?
您可以为该矩形主体和您的其他主体(星形或水果)设置用户数据。您还必须扩展 b2contactlistner(cocos2d-x)。方法很少
void BeginContact(b2Contact* contact) { /* handle begin event */ }
void EndContact(b2Contact* contact) { /* handle end event */ }
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
其中一种方法是获取车身用户数据并检查您的火车车身用户数据是否与其他车身用户数据发生冲突。
例如
void HelloWorld::BeginContact(b2Contact* contact)
{
b2Body * bodyA = contact->GetFixtureA()->GetBody();
b2Body * bodyB = contact->GetFixtureB()->GetBody();
// CCSprite sp1 = (CCSprite*)bodyA->GetUserData();
// CCSprite sp2 = (CCSprite*)bodyB->GetUserData();
// b2Body *b1 = (new Layerhero())->b1;
CCLog("In the begincontact");
if((bodyA == hero && bodyB == hero2))
{
CCLog("In the begincontact1");
boo = true;
}
else if ((bodyA == hero && bodyB == hero3))
{
CCLog("In the begincontact2");
boo = true;
}
}