有一個「實體」類持有參考Box2D的身體並執行操作上也絕對是走的好方法。如果你有一個Spaceship類和一個Meteor類,他們每個人都可以提供他們自己的控制身體的派生方法(AI),但是他們每個人都有共同的邏輯和代碼來支持「有物體的事物」的操作例如普通的「實體」基類)。我認爲你在正確的軌道上。
它當觸點開始發生變得有點模糊。這是您開始進入整個系統架構的地方,而不僅僅是物理世界的結構或單個Coco2d場景。
這裏是我如何在過去做到了這一點:
首先,我建立了聯繫監聽器,如下所示:
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)
{
b2Fixture* fixtureA = contact->GetFixtureA();
b2Body* bodyA = fixtureA->GetBody();
Entity* entityA = bodyA->GetUserData();
b2Fixture* fixtureB = contact->GetFixtureB();
b2Body* bodyB = fixtureB->GetBody();
Entity* entityB = bodyB->GetUserData();
if(test if entityA and entityB should not have collision response)
{
contact->SetEnabled(false);
}
// Do this if you want there to be collision notification, even if
// there is no response.
AddContactPair(entA,entB);
}
void AddContactPair(Entity* entA, Entity* entB)
{
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 BeginContact(b2Contact* contact)
{
Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();
assert(entA != NULL);
assert(entB != NULL);
// Not sure this is still needed if you add it in the pre-solve.
// May not be necessary...
AddContactPair(entA, entB);
}
// BEWARE: You may get multiple calls for the same event.
void EndContact(b2Contact* contact)
{
}
};
的由於發動機的工作方式,你可以得到多個聯繫人擊中相同的身體。這個監聽器對它們進行過濾,所以如果兩個實體發生碰撞,你只能得到一條消息。
監聽器只店已經發生的衝突。可以對其進行修改以進一步將它們分爲「開始」和「結束」以用於其他目的。在這裏,聯繫意味着「你已經被某些東西擊中了」。我不需要知道它是否停止了聯繫。
到NotifyCollisions調用是「祕密武器」。它向被聯繫的實體發送一條消息(通過消息系統)他們碰到了一些東西,而另一個實體是他們碰到的東西。子彈擊中船。子彈摧毀自我。船舶根據項目符號屬性(GetDamageInflicted()方法)自我傷害。這反過來指示圖形系統從顯示器上移除子彈。如果該船被摧毀,它也會被摧毀。
從總體執行角度看: 開始之前,分配聯繫人偵聽器。
遊戲的每個週期: 在所有實體上調用「更新」。這更新他們的物理力量等。 更新Box2d世界。 在監聽器上調用NotifyCollisions。 從系統中刪除死亡實體。
對您有幫助嗎?
我仍然迷路。我有3個實體 - 貓,老鼠,地形。貓和老鼠都應該與地形相撞,但不能與對方相撞。當貓與鼠標碰撞(反之亦然)時,我不希望它們成爲碰撞響應,我只想移除鼠標,並讓貓繼續正常運行。根據您的代碼,我會看到如何獲得(我已經有過類似的東西),但是我不知道如何防止物理衝突繼續/或者讓它繼續,這取決於它是貓/鼠接觸還是貓/地形或鼠標/地形接觸。 –
我修改了PreSolve事件來處理這個。您在那裏檢測到碰撞,取消繼續處理碰撞(contact-> SetEnabled(false)),但將其添加到「已聯繫」列表中,以便稍後處理。查看PreSolve事件的手冊,併爲此使用非常類似的示例。 – FuzzyBunnySlippers
@John這是否回答您的問題? – FuzzyBunnySlippers