Search code examples
ioscollision-detectionbox2d

Box2D Contact Listener?


I am trying to use the Box2D contact listener in my game. I know Ray Wenderlich has a tutorial on how to do this but I find it confusing and I wanted to see if someone could help explain to me how to do this.

Do I need to have a specific class just for this contact listener or can it just be a few basic lines of code in my CCScene class?

Can someone offer some insight on this?

Thanks!!!


Solution

  • You have to implement a new class for the collision or say contact listener based on some criteria as tag no. i have an example for you.

    // ContactListener.h

    #import "Box2D.h"
    
    class ContactListener : public b2ContactListener 
    {
    private: 
        void BeginContact(b2Contact* contact);
        void EndContact(b2Contact* contact);
    };
    

    // ContactListener.mm

    #import "ContactListener.h"
    #import "cocos2d.h"
    #import "BodyNode.h"
    #import "GameScene.h"
    
    void ContactListener::BeginContact(b2Contact* contact)
    {
        b2Body* bodyA = contact->GetFixtureA()->GetBody();
        b2Body* bodyB = contact->GetFixtureB()->GetBody();
        if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
        {
            BodyNode* bNodeA = (BodyNode*)bodyA->GetUserData();
            BodyNode* bNodeB = (BodyNode*)bodyB->GetUserData();
    
            if ((bNodeA.tag == GameSceneNodeTagBall && bNodeB.tag == GameSceneNodeTagHole) || 
                (bNodeA.tag == GameSceneNodeTagHole && bNodeB.tag == GameSceneNodeTagBall)) 
            {
                switch (bNodeA.tag) {
                    case GameSceneNodeTagBall:
                        if ([bNodeA isKindOfClass:[Ball class]]) {
                            Ball* ball = (Ball*)bNodeA;
                            ball.sprite.visible = NO;
                            [[GameScene sharedGameScene] gameOver];
                        }
                        break;
                    case GameSceneNodeTagHole:
                        if ([bNodeB isKindOfClass:[Ball class]]) {
                            Ball* ball = (Ball*)bNodeB;
                            ball.sprite.visible = NO;
                            [[GameScene sharedGameScene] gameOver];
                        }
                        break;
    
                    default:
                        break;
                }
            }
        }
    }
    

    This is an example of ball and hole collision. You can use this as per your requirement.

    Hope this will help you.

    Thanks!

    to check the collision only for one time :

    // ContactListener.mm
    
        #import "ContactListener.h"
        #import "cocos2d.h"
        #import "BodyNode.h"
        #import "GameScene.h"
    
        void ContactListener::BeginContact(b2Contact* contact)
        {
            b2Body* bodyA = contact->GetFixtureA()->GetBody();
            b2Body* bodyB = contact->GetFixtureB()->GetBody();
            if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
            {
                BodyNode* bNodeA = (BodyNode*)bodyA->GetUserData();
                BodyNode* bNodeB = (BodyNode*)bodyB->GetUserData();
    
                if ((bNodeA.tag == GameSceneNodeTagBall && bNodeB.tag == GameSceneNodeTagHole) || 
                    (bNodeA.tag == GameSceneNodeTagHole && bNodeB.tag == GameSceneNodeTagBall)) 
                {
                    switch (bNodeA.tag) {
                        case GameSceneNodeTagBall:
                            if ([bNodeA isKindOfClass:[Ball class]] && isBallCollision == NO) {
                                Ball* ball = (Ball*)bNodeA;
                                ball.sprite.visible = NO;
                                isBallCollision = YES;
                                [[GameScene sharedGameScene] gameOver];
                            }
                            break;
                        case GameSceneNodeTagHole:
                            if ([bNodeB isKindOfClass:[Ball class]] && isBallCollision == NO) {
                                Ball* ball = (Ball*)bNodeB;
                                ball.sprite.visible = NO;
                                isBallCollision = YES;
                                [[GameScene sharedGameScene] gameOver];
                            }
                            break;
    
                        default:
                               isBallCollision = NO;
                            break;
                    }
                }
            }
        }