Wednesday, December 30, 2015

This is Why I Love Phaser

One of my stated goals when I started the Amphibian.com web comic was to include interactive experiences directly in the comics. My idea is that this kind of thing takes web comics more towards the web. It uses more of the browser as a medium. It's the next level of comics.

That means every so often, when the joke calls for it, I include some interactive or dynamic content in the comics. Today's comic has a game embedded in the third frame.

And that's why I love Phaser.

I had to take a break from working on my platformer to make today's hedge maze game, but thanks to Phaser it didn't take all that long. I only wrote somewhere around 150 lines of code and I have a small game playable in a desktop browser. When I first tried Phaser (making my 404 page game) I was a little skeptical. I am very careful about which frameworks I use for any of my projects, but at this point I am totally sold on Phaser as an HTML5 game development framework. It just saves me so much time. The way it works makes sense, and it performs very well. Prior "games" that I've put in the comics have taken a lot more time to develop and done a lot less than this hedge maze one today. Expect to see more like this in the future.

I don't mention it often anymore, but the entire source code for Amphibian.com is on GitHub, and that includes the JavaScript for the hedge maze game. Check it out here and use it to start making your own games!

Amphibian.com comic for 30 December 2015

Monday, December 28, 2015

More Levels, Fewer States

A New Level
Last week when I added a second level to my platformer, I used multiple Phaser State objects. I had one for each level plus one for the "select a level" mode. While this worked, I wasn't particularly happy with it because every one of the level's State object was identical. It seemed to me that there should have been a better way.

As is often the case with me, I work on these games late at night and usually only for an hour or so, and I don't think of what is later the obvious solution until I've been away from it for a while. Over the weekend, I came to the conclusion that I should only be using a single State for all the different levels and merely changing which map gets loaded by other means.

Here are those other means... First, I created some simple objects which contain the map and music asset keys for each level. I put them all in a map inside an object I called gameState. This is different from a Phaser State object - I use it to keep track of my own personal state information. So far, that means which map is being played and what background music to use. I pass this gameState object to the constructors for both the stage select and the playable stage.

var sandboxLevel = {
        map: "LevelSandbox",
        music: "Ouroboros"
};

var levelOne = {
        map: "Level1",
        music: "DangerStorm"
};

var gameState = {
        levels: [],
        currentLevel: "sb"
};

gameState.levels["sb"] = sandboxLevel;
gameState.levels["one"] = levelOne;

var theStage = stage(gameState);
var stageSelectState = selectStage(gameState);

var game = new Phaser.Game(width, height, Phaser.CANVAS, "gameArea");

game.state.add("stageSelect", stageSelectState, true);
game.state.add("level", theStage);

As you can see in my code snippets above, I now only have to add two States to the Game. Inside the update function for the stage select state, I simply manipulate my gameState object before switching the Phaser State to the playable level.

function update() {

    if (keys.s.isDown) {
        // sandbox level is selected...
        gameState.currentLevel = "sb";
        this.state.start("level");
    } else if (keys.o.isDown) {
        // level one is selected...
        gameState.currentLevel = "one";
     this.state.start("level");
    }

}

Once a new State is started, the create function gets called on it. In my create function, I use the gameState object to get the current level's map and background music.

function create() {

    mapKey = gameState.levels[gameState.currentLevel].map;
    musicKey = gameState.levels[gameState.currentLevel].music;

    // ... other stuff ...

    var map = this.add.tilemap(mapKey);
    var bgmusic = this.sound.add(musicKey);

    // ... other stuff ...

}

That's it. I like this much better than that first attempt. It should be trivial now to add as many stages as I want. I really only want 8. But anyway...

You can play the game at http://amphibian.com/eight-bit and you can view the complete source code on GitHub. Take a look at today's comic before you go. I brought back Science Frog doing tech support for the other frogs, because it's funny.

Amphibian.com comic for 28 December 2015

Friday, December 25, 2015

Merry Christmas!

This will be a short post today, and contain no significant content. I figure everyone will probably be doing something more important that reading my blog today, Christmas 2015.

Anyway, I hope you read and enjoyed my Amphibian.com version of A Christmas Carol. In the end, today's comic, the CEO frog decides to never give thoughtless gifts again. I feel like it's an important lesson for all of us today. But I was surprised to learn that it was an important lesson for us 100 years ago - a lesson that NO ONE LEARNED!

That's right, over a hundred years ago Eleanor Robson Belmont started the organization known as SPUG - the Society for the Prevention of Useless Giving. It was a response to what was seen as wasteful spending on gifts for the sake of gifts at Christmastime. Sound familiar? I guess some things never change. SPUG got a lot of attention back in the second decade of the twentieth century, but the outbreak of World War I took the focus off of revolutionizing the way Christmas was celebrated. The Society doesn't officially exist anymore.

Maybe it's time for a comeback?

In any event, have yourself a Merry Christmas. I'll post again on Monday with some more progress on my platformer and we'll all play it and be joyous as we await the start of 2016.

Amphibian.com comic for 25 December 2015

Wednesday, December 23, 2015

Adding More Stages to my Phaser Platformer

Last week I started getting my platformer set up to have more than just one stage. I created some State objects, one for the title screen and one for the sandbox stage. Today I wanted to continue that process by adding a second playable stage.

Let's call this new stage Stage 1. I think I'm going to number the stages by the bit positions, so we'll have Stage 1 (1), Stage 2 (10), Stage 4 (100), etc. For now, I'm going to leave the sandbox stage in there as Stage 0.

Because of the groundwork I laid over this past weekend, adding the additional stage was easy. If you remember, I created a playingState function which returned a Phaser State object representing the playable stage. Today, I modified that function and renamed it to stage. It now takes a single numeric argument and uses that to select which map and music will be loaded.

Here is a simplified example of my code:

function stage(n) {

    var thisLevel = n;

    // ... other variable declarations

    function preload() {
        this.load.pack("main", "assets/pack.json");
    }

    function create() {

        // load the map for thisLevel
        map = this.add.tilemap("stage" + thisLevel);

        // load the music for thisLevel
        bgmusic = this.sound.add("bgmusic" + thisLevel);

        // ... all the other stuff ...

    }

    // ... all the other functions ...

    return {
        preload: preload,
        create: create,
        update: update
    };

}

For the above code to work as expected, I had to add more game assets to my pack.json file. I now have two tilesets with keys stage0 and stage1, and two audio types with keys bgmusic0 and bgmusic1. Adding more stages is as simple as adding more tilesets and music to the asset pack.

In the game setup, I simply call stage twice. The first time to create the State object for the sandbox and the second time to create the State object for stage 1.

var stageSelectState = selectStage();

var sandboxStage = stage(0);
var stageOne     = stage(1);

var game = new Phaser.Game(width, height, Phaser.CANVAS, "gameArea",
  stageSelectState);

game.state.add("sandbox", sandboxStage);
game.state.add("one", stageOne);

While this works and was fairly simple, it bothers me a little bit. Since 99% of the stage is exactly the same (the only behavior that differs based on the input parameter is in the create function) I really hate calling the stage function more than once, each time creating a functionally identical closure. I think I'm going to optimize this a little more. Stay tuned.

As I've mentioned before, you can play the in-progress game at https://amphibian.com/eight-bit and you can check out the complete source code on GitHub. Leave a comment with any feedback, and don't forget to read today's comic. It's part 4 of my Christmas story and includes the third and final goat!

Amphibian.com comic for 23 December 2015

Monday, December 21, 2015

The Gift of No Gift

Merry Christmas!

I hope everyone is looking forward to Christmas this Friday for all the right reasons. It's gotten difficult to teach my children that Christmas isn't about providing a list of expensive items that will be purchased for them in exchange for good behavior. The Santa-Industrial Complex is working hard to convince us all that we need to buy stuff for everyone we love this time of year.

The series of comics I'm running right now at Amphibian.com is my attempt to poke fun at this modern tradition. Last week, the Goat of Christmas Past reminded the CEO frog that no matter how good presents might seem, they don't last. Odds are, you don't currently have many (if any at all) gifts you were given as a child that are still valuable to you today. In today's comic, the Goat of Christmas Present shows the frog that too many people are giving gifts that aren't really needed. How many coffee mugs do you really use?

Please don't think I'm some kind of villain worthy of mention in a Dickens story. I don't hate the giving of gifts on Christmas. I am just suggesting that as a society we should take a closer look at our motivations. Why do we go crazy and spend $59 bazillion between Thanksgiving and Christmas each year? Is it because we've all lost the ability to show our love for each other without enlisting the help of Wal-Mart and Target?

There is an aspect of the gift-giving craze that I suspect few people stop to consider. Many people don't feel loved when they are receiving gifts. At least that's what Gary Chapman wrote in his book about the Five Love Languages. While there seems to have been little research done to confirm his theories, I've read it and it does seems to fit extremely well with my experiences. Some people feel love by receiving gifts. But a bunch of other people don't, or at least not as much. So if our goal at Christmas is really to show our love for each other, shouldn't we desire to do that in the way the recipient will most feel love? There's a good chance that won't be a gift.

But if we're really just buying gifts because advertising agencies have fooled us into believing that we need to in order to conform to the Christmas rules, maybe we should stop.

Just something to think about.

Amphibian.com comic for 21 December 2015

Friday, December 18, 2015

Using Game States in Phaser

The game's (temporary) Title Screen
If you've tried playing the sandbox level for the 8-bit style platformer I've been building with Phaser, you have seen that it just drops you right into the stage. There's no splash screen or level selector or how-to-play instructions. It's just *BAM* do something! Today I decided to change that.

Making different types of screens with Phaser means working with different States. What is a State? In its simplest form, a State is just a set of functions - preload, create, update, and (optionally) render. When you first switch to a State, preload and create are called. Then update is called continuously until you do something to change the State. If you create a very simple game (like mine has been so far) you might only have one State and you might not even call it that - you can just pass in an anonymous State object when you create the game!

Here's what I mean... Look at this example of what my code was like before:

function preload() {
    // ... do preload stuff ...
}

function create() {
    // ... do create stuff ...
}

function update() {
    // ... do update stuff ...
}

// ... define a bunch of other functions and variables ...

var game = new Phaser.Game(width, height, Phaser.CANVAS, "gameArea", {
    preload: preload,
    create: create,
    update: update
});

Basically, I was creating a State object inline with the call to the Game constructor. It was a simple object that defined the 4 functions I mentioned previously. As soon as the Game was created, this State started running. It's possible to create multiple States using different combinations of globally-defined functions, like the code above, but that would get ugly fast. I know this isn't exactly OO, but I still want to practice good encapsulation. I want separation of concerns.

What did I do? I created two functions which generate the two different states! One for the simple title screen and one for the game as it has been up to this point. The title screen state just shows a single image and waits for the player to push the 'S' key. Once pushed, the update function in the title state changes the game state to the playable sandbox state.

Here's a much simplified version of the code:

/**
 * Creates the game state which defines the title screen.
 */
function titleState() {

    var keys;
    var splash;
    
    function preload() {
        this.load.pack("main", "assets/titlePack.json");
    }
    
    function create() {
        splash = this.add.image(0, 0, "title");
        keys = this.input.keyboard.addKeys({
            's'  : Phaser.KeyCode.S
        });
    }
    
    function update() {
        if (keys.s.isDown) {
            this.state.start("sandbox");
        }
    }
    
    return {
        preload: preload,
        create: create,
        update: update
    };
    
}

/**
 * Creates the game state which defines the playable level.
 */
function playingState() {

    // ... define private variables ...
    
    function preload() {
        this.load.pack("main", "assets/pack.json");
    }
    
    function create() {
        // ... all the game creation stuff ...
    }
    
    function update() {
        // ... all the game update stuff ...
    }
    
    return {
        preload: preload,
        create: create,
        update: update
    };
    
}

// Now we create the states and the game

var title = titleState();
var sandbox = playingState();

var game = new Phaser.Game(width, height, Phaser.CANVAS, "gameArea", title);

game.state.add("sandbox", sandbox);

The "main" game setup is much simpler now - it just creates the state objects and then the Game. The game starts with title as the running state, but adds the sandbox state with the key "sandbox." The key is important because that's what you have to use when you want to switch states.

The other thing to note is that in the State preload, create, and update functions, the this variable will refer to the Game object. That fact becomes important when you are creating in-game objects in these functions.

Check out the game with its fancy new title screen here: http://amphibian.com/eight-bit/, and visit the project page on GitHub if you'd like to see the complete source code. Over at Amphibian.com, today is Chapter 2 of my Christmas story - give it a quick read!

Amphibian.com comic for 18 December 2015

Wednesday, December 16, 2015

Let's Add More Weapons to my Phaser Platformer

After adding the health meter earlier this week, the playable sandbox level for my platformer built with Phaser was looking much more complete. There are just a few more things I need to add before I switch my focus to level design and make a legitimate game out of it. One of those things is more weapons.

My plan for the game is to make it similar to a classic 8-bit Mega Man game. In those, after defeating one of the bosses, Mega Man could use the weapon from that boss. To make that happen in my game, I'd have to expand the weapons capability. I needed to add the ability to switch to different weapons that each had different qualities.

To begin, I defined an array of weapon objects. Each object would have its own name, velocity attributes, and power to damage enemies. For each of these weapon types, I will create a Phaser Group to manage them. All the weapon groups will be added as children of an overall weapons group. Look at this code from my create function:

function create() {

    // ... other stuff ...

    weaponsGroup = game.add.group();
    weapons = [];
    weapons.push({
       name: 'pencil',
       lifespan: 1500,
       velocity: {
           x: 500,
           y: -400
       },
       spin: 50,
       power: 10
    });

    weapons.push({
        name: 'flask',
        lifespan: 1500,
        velocity: {
            x: 600,
            y: -600
        },
        spin: 50,
        power: 20
     });

    weapons.push({
        name: 'hammer',
        lifespan: 1500,
        velocity: {
            x: 600,
            y: -400
        },
        spin: 50,
        power: 30
     });

    weapons.push({
        name: 'brace',
        lifespan: 1500,
        velocity: {
            x: 800,
            y: -200
        },
        spin: 80,
        power: 40
     });

    for (var w = 0; w < weapons.length; w++) {
        var wg = game.add.group();
        wg.createMultiple(3, weapons[w].name, 0, false);
        weapons[w].sprites = wg;
        weaponsGroup.add(wg);
    }

    // ... other stuff ...

}

The overall group, weaponsGroup, is created first. Then I set up an array of 4 weapon types. The name is important because I have it set up to match the sprite asset key for that weapon. I then loop over the weapons array and create a group just for a set of those weapons. I set that group as the sprites field on the weapon object - I'll need to reference it later. Also, those groups are added as children of the weaponsGroup.

At this point I have a group of weapons groups. Any of these can be use to strike an enemy, so they must be checked for enemy collisions. A slight change in my update function takes care of that. The overlap function can take an array of groups in addition to a single group, and the children field of a Group object is the array of child groups!

function update() {

    // ... other collision checks ...

    game.physics.arcade.overlap(enemies, weaponsGroup.children, hurtEnemy, null, this);

    // ... other stuff ...

}

Okay, so how do I have the frog throw a particular type of weapon? First, I added a variable to the game called weaponIndex. It is set to the index of whatever weapon is currently active. So far, I have 4 weapons which means that the index can be 0, 1, 2, or 3. Then in my throwSomething function, I get the weapon object out of the weapons array using the index and use its properties to perform the toss.

function throwSomething() {

    // has it been long enough? can we throw something yet?
    if (game.time.now > nextFire) {

        nextFire = game.time.now + FIRE_RATE;

        // see if a weapon is available from the group
        var weapon = weapons[weaponIndex].sprites.getFirstExists(false);
        if (weapon) {

            weapon.exists = true;
            weapon.anchor.setTo(0.5, 0.5);
            weapon.reset(frog.body.position.x+20, frog.body.position.y-20);
            game.physics.arcade.enable(weapon);

            weapon.lifespan = weapons[weaponIndex].lifespan;
            weapon.body.angularVelocity = weapons[weaponIndex].spin;
            weapon.body.velocity.y = weapons[weaponIndex].velocity.y;
            weapon.power = weapons[weaponIndex].power;
            if (frog.scale.x == 1) {
                weapon.body.velocity.x = weapons[weaponIndex].velocity.x;
            } else{
                weapon.body.velocity.x = -weapons[weaponIndex].velocity.x;
            }
            
        }

    }

}

This code is very similar to what I had before, when the only weapon was the pencil. The differences are that the sprite, lifespan, velocity, and power are pulled from the weapon object in the weapons array instead of always being hard-coded to the same values.

One final change was to the function that handles hurting the enemies when there is a collision between a weapon and an enemy. Previously, I used a fixed damage value for the enemy. Now, the damage to the enemy is based on the power field of the particular weapon that is hitting it. For example, it takes 4 hits with a pencil to kill a toad but only 1 hit from a curly brace.

function hurtEnemy(e, w) {

    if (!e.immune) {
        e.immune = true;
        e.alpha = 0.5;

        // damage to enemy = power of weapon
        e.damage(w.power);

        w.exists = false;

        game.time.events.add(200, function() {
            e.immune = false;
            e.alpha = 1;
        }, this);
    }

}

The hurtEnemy function is what gets called when overlap is detected between a sprite in the enemies group and a sprite in one of the weapons groups. The first parameter e will be the enemy object and the second parameter w will be the weapon that hit it. Since my throwSomething function set the power field on the weapon sprite to match the power field on the weapon definition, I can read that property here to control the amount of damage to the enemy.

Want to give it a try for yourself? Play the game here: http://amphibian.com/eight-bit/. Just hit 1 through 4 on the keyboard to switch between the different weapons. If you'd like to see the complete source code, it's on GitHub.

As for comics today, this is the first of a 5-part Christmas story. It roughly follows the pattern of Dicken's A Christmas Carol, but...well, you'll see. They're a bit longer than the normal ones, but don't take too much longer to read. I hope you enjoy them!

Amphibian.com comic for 16 December 2015