Developer Diary: Jetpack game HTML5 – Day 3

Milestone of the day:
Create player collision with enemies

Day 3: Creating/detecting player collision

Today I’m going to add collision to the game. This can be quite difficult at first, but Box2D allows us to do this very easily.

How to add collision using Box2D then? Let me explain trough some code.

    var world;
    var _contacts = [];

    //Add the contactlistener and bind the Crafty EnterFrame
    var contactListener = new Box2D.Dynamics.b2ContactListener;
    contactListener.BeginContact = function(contact)
    {
        var myContact = {
            fixtureA: contact.GetFixtureA(),
            fixtureB: contact.GetFixtureB()
        };
        _contacts.push(myContact);
    console.log("Contact!");
    }

    contactListener.EndContact = function(contact)
    {
        var myContact = {
            fixtureA: contact.GetFixtureA(),
            fixtureB: contact.GetFixtureB()
        };

        var totalContacts = _contacts.length;
        for(var i = 0; i < totalContacts; ++i){
            if ((_contacts[i].fixtureA == myContact.fixtureA) &&
                (_contacts[i].fixtureB == myContact.fixtureB)) {
                _contacts.splice(i, 1);
                return;
            }
        }
    };

    world.SetContactListener(contactListener);
    console.log("initGame()>>> Contact listener added");

So first we create a contactListener. This will listen and react to any contact in the physics world.
We then tell it what to do when the contact begins. (contactListener.BeginContact) In that function, we create a variable myContact that holds the fixture information of the collision.
We then push that information to the global variable _contacts. I also logged it in the console whenever a collision occurred to see if the listener was working, but remember to comment it when you got it working.

I will not explain the second function. (contactListener.EndContact)
The only thing it does is update the _contacts variable by removing the contacts (and the fixtures) that are no longer colliding.

Lastly, we have to assign the world a ContactListener using the function: 

world.SetContactListener(contactListener);

That’s it for adding a ContactListener.

Now we have to do something with it. Again, I will show you the code first.

    //Handle contacts
    var totalContacts = _contacts.length;

    for(var i = 0; i < totalContacts; ++i)
    {
        var contact = _contacts[i];

        if(contact)
        {
            //Assign the bodies that are touching to a variable
            var bodyA = contact.fixtureA.GetBody();
            var bodyB = contact.fixtureB.GetBody();

            //Check to see if the body has userData
            if ((bodyA.GetUserData()) && (bodyB.GetUserData()))
            {
                var spriteA = bodyA.GetUserData(); //Get the userData (a Crafty entity)
                var spriteB = bodyB.GetUserData();

                // Check to see if you've hit an enemy
                if (spriteA.isPlayer && spriteB.isEnemy || spriteA.isEnemy && spriteB.isPlayer)
                {
                    Crafty.scene("game_over");
                }
            }
        }
    }

The .isPlayer and .isEnemy are attributes that I’ve added to the crafty entity. Like so:

plyr = Crafty.e("player")
    .attr({
        w: 24,
        h:38,
        isPlayer: true
    });
var enmy = Crafty.e("enemy")
    .attr({
        width: 52,
        height:52,
        isEnemy: true
    });
var enmy_rocket = Crafty.e("rocket")
    .attr({
        width: 66,
        height: 66,
        isEnemy: true
    });

Note how both enemy and rocket have the isEnemy boolean set to true. This means that they both can destroy the player.

Michiel De Mey

Full-time geek, Full Stack Engineer and Full Metal Hero. NodeJs, AngularJs, API design, WebSockets, WebSec & IoT enthusiast. Former San Francisco resident.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus