Step 04: A bullet? A meteor? Collide!

Remember that collision types we set to the bullet and the meteor shapes in the previous step? Here how we can use it to hook the callback on collison. But we also need to set the collision type for the floor shape to hook the collision of meteor and the floor.

onLoad: function () {
    // Create physics space
    this.space = new cp.Space();
    this.space.gravity = cp.v(0, this.gravity);

    // Add game floor
    const floor = new cp.SegmentShape(
        this.space.staticBody,
        cp.v(0, 20),
        cp.v(2000, 100),
        10
    );
    floor.setCollisionType(FLOOR_SHAPE);
    this.space.addStaticShape(floor);

    // create verts for physics
    this.bulletVerts = createVertsFromRect(this.bulletSprite.getRect());
    this.meteorVerts = createVertsFromRect(this.meteorSprite.getRect());

    // create collision handlers
    const shapesToRemove = this.shapesToRemove = [];
    this.space.addCollisionHandler(METEOR_SHAPE, BULLET_SHAPE, (arbiter, space) => {
        const { a, b } = arbiter;

        // We can not remove shapes and bodies just now,
        // it is forbidden during physics space step.
        // So we keep it to remove after physics step is done.            
        shapesToRemove.push(a);
        shapesToRemove.push(b);
        return true;
    });

    // Handle case when meteor touches the ground
    this.space.addCollisionHandler(FLOOR_SHAPE, METEOR_SHAPE, (arbiter, space) => {
        const { b } = arbiter;
        shapesToRemove.push(b);
        return true;
    });
},

Here is the full code. I added to callbacks. One for bullet collision with the meteor and other for the meteor hitting the floor. The collision callback takes two arguments the 'arbiter' and the 'space'. You can use the 'arbiter' to reach the colliding bodies and shapes.

The important thing here is that we can not simply remove shapes and bodies from the physical space, beacuse we are in the middle of the physics engine step. The solution is pretty simple - remember colliding shapes you would like to remove, and remove it later when the physics step is finished. I did it in the update method of the game component:

update: function (dt) {
    const { space, shapesToRemove } = this;
    if (space) {
        space.step(dt);
        if (shapesToRemove.length > 0) {
            for (let i = 0; i < shapesToRemove.length; i++) {
                const shape = shapesToRemove[i];
                // Remove shapes from space
                space.removeShape(shape);
                // Remove bodies from space
                space.removeBody(shape.body);
                // Destroy nodes (saved as userData)
                shape.body.userData.destroy();
            }
            shapesToRemove.length = 0;
        }
    }
},

But to be able to reference back to the cocos engine node we need to store it with the shape, so simply add it as userData field when creating a shape.

shape.userData = node;

Wow, everything is flying and colliding. Bullets even destory the meteors! That is a lot of work, but i think we need more special effects to make our game more alive. Lets do it in the next step.

you can checkout git tag step0w to review the code

Step 05