Monday, March 23, 2015

First Modifications for GGO15

After finally selecting a game to fork last week, I was able to start work on my GitHub Game Off 2015 entry this weekend.

The game I chose to modify was Octocat Jump from the 2012 Game Off, which used the Crafty game framework. Typically I stay away from frameworks that try to do "too much" for me...I tend to find myself fighting against them to do things the way I want and there's also typically a performance penalty that must be paid. However, I have so far been very impressed by Crafty and would definitely use it in a future JavaScript game project.

You can play my version at http://caseyleonard.com/ggo15.

So far, the changes I've made to the game are relatively minor.

1. Updated the dependencies.


Since the game I forked has been pretty much untouched since late 2012, the versions of jQuery and Crafty used in it were a bit out-of-date. The first thing I did was update them to the current releases. The upgrade to jQuery had no impact, but a few things had changed with Crafty over the years which broke the game.

Somewhere between the version used in Octocat Jump and the version released last November, the method of specifying animations changed significantly. You used to be able to specify an animated sprite like this

Crafty.e("2D, DOM, Portal, SpriteAnimation")
    .animate("portal", 0, 0, 10)
    .animate("portal", 5, 0);

But now you have to create a reel first before starting animation. Here is the updated code.

Crafty.e("2D, DOM, Portal, SpriteAnimation")
    .reel("portal", 500, 0, 0, 10)
    .animate("portal", 1)

I should explain a little about what's going on here. When using Crafty, everything in your game is called an Entity. The hero, enemies, power-ups, obstacles, everything. All Entities. To create an Entity, you just call Crafty.e("components_string"). The components string specifies what type of Entity you want to create. It's just a comma-delimited list of components. Your Entity will have the properties of everything in the list - it's basically a multiple inheritance pattern. In the example above, my Entity gets all the properties of a 2D, DOM, Portal, and SpriteAnimation component. Some of those are built-in components, but you can also define your own types. You can even just use a "type" that has no special meaning in order to tag that entity for other things later, such as which types of Entities create collisions against each other.

The code I modified, shown above, created an animated sprite Entity. The Entity inherits the reel and animate functions from the SpriteAnimation component. You can create multiple reels for each Entity if you want, and then select which one to play at different times by calling animate with two arguments: the name of the real and the number of times to loop through it. The example above starts an animation reel called "portal" that plays once immediately after creating the Entity and defining the reel.

2. Changed the Characters and Fonts


In my game I want to use one of my frogs from Amphibian.com instead of the Octocat. I mean, I like Octocat and all, but I have my own characters. I'm going to use Business Frog and modify the game so that he's jumping around navigating the twisted world of project management. I also changed the fonts used in the game to the same one I use on my comic (Sniglet, if you're curious).

First draft of the Business Frog sprite sheet (needs work)

3. Fixed Some Bugs


There are a few bugs in the original game that I fixed, which turned out to be a good exercise in learning how things work in a Crafty game.

The first was that near the beginning of the game, there seemed to be a platform missing. I'm not sure if it was that way by design or not, but it really bothered me. I tracked it down to where the level data is turned into platform entities. At the start of the game, there should be 10 platforms before the new platforms start coming down from above. There was an array.slice() call being made that only selected 9 elements instead of 10.

The second thing might not be considered a bug, but was certainly an important missing feature. In the original, there was no way to restart the game after you fall. You had to refresh the whole page in your browser. I added a keyboard event listener on the game-over scene that sends you back to the main scene - but had to reset the value of an internal variable n back to the start value of 10 in order for the game to work properly after a restart. I added that line to the initState() function, where it probably should have been all along.

The last thing weird thing I fixed was the pause behavior, but I think this one was my fault. The game was designed to show a dark overlay with the word "Paused" in the middle of the screen when you pause it. I believe the Crafty API must have changed somewhere between 2012 and today because it had incorrect behavior on my version but seemed to work on the original.

Crafty.bind("Pause", function onPause() {
    Crafty("BackgroundOverlay").color("#000000");
    Crafty("BackgroundOverlay").alpha = 0.5;
    Crafty("PauseText").destroy();
    Crafty.e("2D, DOM, Text, PauseText").css({
        "text-align": "center",
        "color": "#fff",
        "textShadow": "0px 2px 8px rgba(0,0,0,.9), -1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000"
    }).attr({
        x: 0,
        y: Crafty.viewport.height / 2 - Crafty.viewport.y - 64,
        w: Crafty.viewport.width,
        z: 9999
    }).textFont({
        "family": "Sniglet",
        "size": "96px"
    }).text("Paused");
    Crafty.trigger("RenderScene");
});

In the original code, the Crafty.trigger("RenderScene") on line 18 was Crafty.DrawManager.draw(). That function is no longer defined on DrawManager, which resulted in the function throwing an uncaught exception and essentially un-pausing the game. Why is either line needed? Because when Crafty pauses, scene rendering doesn't take place - and that overlay and text will never show up. Manually telling it to draw once takes care of the issue. The accepted way to do that in the current API is to trigger the "RenderScene" event.

More To Do


I've really only scratched the surface of the changes I want to make to the game. I mentioned it briefly above, but I want to make it seem like Business Frog is jumping through a poorly managed software project (like he does in the comic). The platforms of different lengths stacked vertically remind me of a Gantt chart, so I want to make some of the platforms "critical path" elements which give you a bonus for hitting sequentially. I also want to add a power-up that temporarily makes the platforms wider. There should also be hoops to jump through. Like actual hoops. Finally, I want to have some kind of projectiles being thrown sideways after reaching a certain height.

I'll probably think of other things as I keep working on it. And just like in 2013, even if I don't win I'll have another game to add to Amphibian.com.

Amphibian.com comic for 23 March 2015