Friday, July 24, 2015

I Have Goals (in my Phaser game)

Maybe I don't have any goals in real life, but I do now have goals in my 404-page Phaser game. Soccer goals.

If you've been reading the blog for the last week or so, you'd know that I am working on a game for the Amphibian.com 404 page - frog soccer. It really doesn't have anything to do with a 404 page, but my kids liked the idea.

I have been very time-constrained this week, so the only things I've added since Wednesday is a new tilemap with field tiles that look like an actual soccer field, and the goals. The new tiles were as easy as drawing some new squares in GIMP and using Tiled again (see Monday's post). But the goals were slightly more interesting.

My goal for the goals was simple. Using an image of the side of the goal (with net) and an image of the top of the goal (again, with net), I could draw the side twice and the top once to create the appearance of a goal viewed from the standard top-down angle. The frog or ball or whatever should be able to walk into the goal and appear under the net.

Here are some pictures to illustrate what I'm talking about.

The side of the goal. Used twice per goal.

The top of the goal. Drawn above the two sides.
The frog standing behind the goal.

The frog standing in the goal. She appears under the net.

The sides of the goal were simple. Just like the trees, I can create them as sprites and give them custom collision bodies. The frog will be able to walk in front of and behind them normally because of the group.sort('bottom', Phaser.Group.SORT_ASCENDING) call on each update. Just like the trees. But what about the top of the goal? And the net that hangs down from it? It should always be on top.

The key is to not put it in the group.

The way I create the top-down effect in the game is to draw the objects that are closer to the bottom of the screen on top of things that are closer to the top. The group.sort() function takes care of this. But that sorts inside the group only. Any other object created before or after the group will always draw either under or above the group.

function create() {

    game.stage.backgroundColor = "0x409d5a";

    map = game.add.tilemap('map');
    map.addTilesetImage('field-tiles', 'tiles');;
    layer = map.createLayer('groundLayer');
    layer.resizeWorld();

    group = game.add.group();

    // this net will always be on top of the group
    var net = game.add.image(-41, 237, 'net');

    // ... add other stuff to group ...
  
    goal1 = group.create(-40, 400, 'goal');
    game.physics.enable(goal1, Phaser.Physics.ARCADE);
    goal1.body.setSize(112, 22, 0, 98);
    goal1.body.immovable = true;

    goal2 = group.create(-40, 240, 'goal');
    game.physics.enable(goal2, Phaser.Physics.ARCADE);
    goal2.body.setSize(112, 22, 0, 98);
    goal2.body.immovable = true;

    // ... do some other stuff ...

}

In my create code above, the first thing I do is create the ground tiles using the tilemap. The very next thing I do is create the group for all the sprites. Now everything in the group will draw above the ground. If I were to move the game.add.group() call to before the game.add.timemap() call, all the sprites in the group end up below the ground. They are there but can't be seen.

I realized this the other day when I was playing around with tilemaps for the first time. So all I have to do to make sure that net is always on top of the goal sides and the frog is to add it to the game after the group. Objects can be added to the group after the net is added, but the group itself must simply be created first.

Remember, the complete source to the game is on GitHub if you want to try things yourself.

I think there's a way to change the draw order of things after you create them, but I haven't been able to get it to work yet. Maybe more on that later. For now, enjoy today's confusing comic about confusing organizational structure.

Amphibian.com comic for 24 July 2015