Exploding sprites with Phaser.js and Shatter.js

I’ve been working on increasing Crash Landing‘s juiciness and one of my first tasks was to make the ground beneath the player explode into pieces. It’s been a great opportunity to  get some use out of Shatter.js.

It wasn’t completely straightforward to figure out how to access the raw image data in order to feed it to Shatter.js, and how to best provide the shattered image back to Phaser. Since I’m loading the sprites from a sprite atlas I need to extract the individual sprite I want to shatter to it’s own image. I could also just load the images individually, but I really wanted to keep the sprite atlas and not load duplicate images.

Next I created a sprite group to contain all the shattered pieces, with each shattered piece placed in it’s correct spot so that when the group is rendered it still visually appears as one object. Then we can interact with the group as a whole and also each sprite individually. To make them explode I just loop through all of them and a random x and y velocity.

Most of the magic is all in ShatterSprite.js which I’ve heavily commented below:


CrashLanding.Util.ShatterSprite = function ShatterSprite(game, key, frame) {
    var numberOfSprites = 12; // make 12 sprites from frame
    var offCanvas = -1000; // constant to create sprites outside of game canvas

    function getImageFromSprite(game, key, frame) {
       // temp sprite used for extraction
       var sprite = game.add.sprite(offCanvas, offCanvas, key, frame);
       // create a canvas to draw the sprite to with Phaser's bitmapData method
       var bmd = game.add.bitmapData(sprite.width, sprite.height);
       // create an image and set the image data, and clean up
       var image = new Image();
       bmd.draw(sprite, 0, 0, sprite.width, sprite.height);
       bmd.update();
       sprite.destroy();
       image.src = bmd.canvas.toDataURL();
       return image;
    }
    
    // Create a phaser group out of a Shatter object
    function createShatteredGroup(game, shatteredImage) {
       var shatteredGroup = game.add.group();
       // Shatter.js returns the new images in an array at Shatter.images, here we loop through all of them
       shatteredImage.images.forEach(function(image, ind, arr) {
          // create a key for the using the same name as the frame of the original sprite + its position in the array of shattered images
          var key = frame + ind;
          // add it to the game cache, so we can add it to the new sprite group
          game.cache.addImage(key, null, image.image);
          var sprite = shatteredGroup.create(offCanvas, offCanvas, key);
          // save the sprites offset so we can place it properly when drawing the groupp
          sprite.originX = image.x;
          sprite.originY = image.y;
          game.physics.arcade.enable(sprite);
          // for the shattered ground objects I only check down collision. Need to move this out and pass in.
          sprite.body.checkCollision.left = false;
          sprite.body.checkCollision.right = false;
          sprite.body.checkCollision.up = false;
       });
       return shatteredGroup;
    }

    return createShatteredGroup(game,
       new Shatter(getImageFromSprite(game, key, frame), numberOfSprites));
}

Once I’ve created my sprite group I can use it to replace sprites/tiles on the screen.  The ground exploding awesomeness takes place in the appropriately named Ground.js. Below, ‘exploder’ is the shattered sprite group and oldTile is the tile I’ve decided to remove from the game world.


oldTile = game.level1map.removeTileWorldXY(removeX, groundLevel, tileWidth, tileHeight);
       // I'm randomly removing tiles, so I make sure there was a tile removed
       if (typeof oldTile != 'undefined') {
          // set shattered group to the previous location of the tile
          exploder.x = oldTile.worldX;
          exploder.y = oldTile.worldY;
          // add each piece at it's proper location within the group and give it some velocity
          exploder.children.forEach(function(sprite) {
             sprite.x = sprite.originX;
             sprite.y = sprite.originY;
             sprite.body.velocity.x = game.rnd.integerInRange(xVelocityMin, xVelocityMax);
             sprite.body.velocity.y = game.rnd.integerInRange(yVelocityMin, yVelocityMax);
          });

There are plenty of improvements we could make, but I think this provides a decent example of how to use Shatter.js with Phaser.js.