2014-01-10 24 views
0

我一直在閱讀關於如何編寫聯繫人監聽器的各種教程,而且我無法將其包圍。如何使用cocos2d編寫box2d聯繫人偵聽器?

這是我到目前爲止有: 在每個班的,我代表物理對象我這樣做:

_body->SetUserData(self); 

我編寫包含以下兩種方法接觸監聽器類:

void ContactListener::BeginContact(b2Contact* contact) 
{ 
    // Box2d objects that collided 
    b2Fixture* fixtureA = contact->GetFixtureA(); 
    b2Fixture* fixtureB = contact->GetFixtureB(); 
    // Sprites that collided 
    MyNode* actorA = (MyNode*) fixtureA->GetBody()->GetUserData(); 
    MyNode* actorB = (MyNode*) fixtureB->GetBody()->GetUserData(); 
} 

void ContactListener::EndContact(b2Contact* contact) 
{ 
    // Box2d objects that collided 
    b2Fixture* fixtureA = contact->GetFixtureA(); 
    b2Fixture* fixtureB = contact->GetFixtureB(); 
    // Sprites that collided 
    MyNode* actorA = (MyNode*) fixtureA->GetBody()->GetUserData(); 
    MyNode* actorB = (MyNode*) fixtureB->GetBody()->GetUserData(); 
} 

我不知道下一步該怎麼做。我現在有兩個正在碰撞的精靈,但我想要做以下事情: 1)當他們碰撞時,我想根據對象的類型從世界中刪除一個精靈。 (例如,如果一個貓的對象和另一是小鼠對象,我想刪除的鼠標對象。

2)欲讓貓對象知道它吃了鼠標

3)欲貓繼續移動,好像它沒有接觸到鼠標。

4)我仍然wan't貓的事情,如地形正常碰撞。

接下來我該做什麼?我對做什麼很無知?如何讓貓繼續與地形正常碰撞,但不能用鼠標碰撞?何時取出鼠標?

回答

0

有一個「實體」類持有參考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。 從系統中刪除死亡實體。

對您有幫助嗎?

+0

我仍然迷路。我有3個實體 - 貓,老鼠,地形。貓和老鼠都應該與地形相撞,但不能與對方相撞。當貓與鼠標碰撞(反之亦然)時,我不希望它們成爲碰撞響應,我只想移除鼠標,並讓貓繼續正常運行。根據您的代碼,我會看到如何獲得(我已經有過類似的東西),但是我不知道如何防止物理衝突繼續/或者讓它繼續,這取決於它是貓/鼠接觸還是貓/地形或鼠標/地形接觸。 –

+0

我修改了PreSolve事件來處理這個。您在那裏檢測到碰撞,取消繼續處理碰撞(contact-> SetEnabled(false)),但將其添加到「已聯繫」列表中,以便稍後處理。查看PreSolve事件的手冊,併爲此使用非常類似的示例。 – FuzzyBunnySlippers

+0

@John這是否回答您的問題? – FuzzyBunnySlippers

相關問題