Friday, August 28, 2015

Comic Formulas

No technical post today, just me getting some thoughts out there about what types of comics seem to work out the best. I've had a lot of time to think about this over the past 13 months.

Four panels seems to be the best length for me. Particularly, I am fond of a 2+1+1 pattern in which the frogs talk back and forth for two frames, a third frame cuts away to another scene, and then in the final frame a punchline is delivered. You'll notice that pattern a lot in my work. I've done some as short as three panels and as many as 8, but four seems to be my favorite.

Obviously, I do a lot of work with puns. I like puns. I think everyone should.

Do you get it?
Over time, I've tried to back away from the really technical jokes. I had a set of comics about the frogs trying to get accepted into the Order of Log N, but I've never published them. There was a log that guided them through a series of tasks related to efficiency of algorithms. You know, O(log n). No, probably not. Unless you are a computer scientist or software engineer you probably have no idea what that means. I'm not saying that I write jokes specifically for an audience. I write the comics for myself, but part of that is my desire to make people laugh. If more people are confused than amused, I don't feel I've accomplished my goal. It's a complicated feeling.

The comics that I like the least are usually the most well-received. I get more compliments about comics that I almost deleted than any others. I'm not sure what's going on. Maybe I over-think things. Maybe I'm too critical of myself. Maybe my sense of humor is shared by no one else in the world.

I have to write what I know. The whole point of Amphibian.com is that the frogs are trying to master and profit from the latest technologies. As a software engineer who was self-trained from age 10 until entering college in 1997, that's what I know. It's what I still do. It's probably what I'll always do. My kids want me to write comics about soccer or gymnastics because that's what they know (I did a game about frog soccer though). I have to explain to them that my work expresses my own experiences and encourage them to write their own comics about their experiences. I am trying to train them to take over writing Amphibian.com someday, but I can't convince any of them to become software engineers.

Today's comic is about something else I know - answering tech support questions. Besides doing this for family members since 1991, I used to work at a small Internet provider back in the days when Windows didn't always come installed with Internet Explorer or even TCP/IP. Helping people over the phone was tough, but there were worse parts. I once had to re-install Windows on a customer's computer because it would no longer boot. After they took the computer home, they called in furious at me because they couldn't find Windows anymore. I asked what was on their screen. Just a little picture that said "My Computer" and another one that said "Recycle Bin." I told them that they were looking at Windows. They called me a liar. I decided that I should get a real job.

Amphibian.com comic for 28 August 2015

Wednesday, August 26, 2015

Pick a Pack of Assets - for Phaser

If you don't care for asset packs,
how about fanny packs? No? Okay.
I performed one more refactor of my Frog Soccer game. In preload, I used to have lots of individual calls to load different types of assets - static images, sprite sheets, audio, and maps. While looking for a way to improve this, I discovered that Phaser supports loading asset packs.

An asset pack is just a JSON-format file that describes sets of game assets. This is then given to the Loader which parses it and then performs all the loads. It is functionally equivalent to putting the individual game.load.image, game.load.spritesheet, game.load.audio, etc. calls in preload. Loading from a pack is just more convenient.

To use it, you first have to make a pack file. It is a JSON file, and that means it must be valid JSON. Unlike in JavaScript where you can leave off the quotes around the field names, a real JSON-format file should always quote every string.

// this is NOT a valid JSON file:
{
    main: [
        {
            type: "image",
            key: "goal",
            url: "assets/images/goal.png"
        }
    ]
}

// but this IS a valid JSON file:
{
    "main": [
        {
            "type": "image",
            "key": "goal",
            "url": "assets/images/goal.png"
        }
    ]
}

The format of the pack files is detailed in the example file located in the Phaser source code: assetPack.json. It supports arbitrary grouping of assets so that you can make sets of assets for different levels of your game, for example. In my game, there is only one "level" so I just put everything in array referenced by the name main.

{
    "main": [
        {
            "type": "image",
            "key": "goal",
            "url": "assets/images/goal.png"
        },
        {
            "type": "image",
            "key": "goal2",
            "url": "assets/images/goal2.png"
        },
        {
            "type": "image",
            "key": "net",
            "url": "assets/images/net.png"
        },
        {
            "type": "image",
            "key": "net2",
            "url": "assets/images/net2.png"
        },
        {
            "type": "image",
            "key": "tiles",
            "url": "assets/images/field-tiles.png"
        },
        {
            "type": "spritesheet",
            "key": "ball",
            "url": "assets/sprites/ball.png",
            "frameWidth": 45,
            "frameHeight": 45
        },
        {
            "type": "spritesheet",
            "key": "frog",
            "url": "assets/sprites/frog.png",
            "frameWidth": 79,
            "frameHeight": 60
        },
        {
            "type": "spritesheet",
            "key": "frog2",
            "url": "assets/sprites/frog2.png",
            "frameWidth": 79,
            "frameHeight": 60
        },
        {
            "type": "audio",
            "key": "whistle",
            "urls": ["assets/audio/whistle.mp3"]
        },
        {
            "type": "tilemap",
            "key": "map",
            "url": "assets/ground.json",
            "data": null,
            "format": "TILED_JSON"
        }
    ]
}

The basic format is that you specify one or more fields consisting of arrays of objects. I have defined one named main. The objects inside the array represent the individual assets that you want to load. Each type has slightly different fields which essentially map to the fields of each type's loader function. They are all listed in the example file I mentioned earlier if you want details . One interesting thing to note is how audio assets use an array of URLs instead of a single one. This is because you often specify a single audio asset in multiple formats to support all web browsers. The rest of the stuff in the file is fairly self-explanatory.

With this in place, my preload method just looks like this:

function preload() {

    game.load.pack("main", "assets/pack.json");

}

Really, that's it. The whole thing. I really like this method. I also really like frogs. Frogs being chased by angry ducks. That's not weird.

Amphibian.com comic for 26 August 2015

Monday, August 24, 2015

Clean Up Your Code

I'm getting towards the end of my work on the Frog Soccer game for my 404 page, so I thought it was about time I cleaned up the code.

I'm (maybe unfortunately) one of those people who make something work first and make it pretty second. In the first cuts of my programs, the code can be very rough. Not optimal at all. Lots of cut-and-paste repetition. Bad stuff. If I don't end up abandoning the project, I usually take another look through it and make it better.

For Frog Soccer, I cleaned up a few things today.

  1. Needless repetition. Creation of both the home team frog and the opponent frog was 99% identical code. I made a createFrog function that replaced both chunks. Same thing for the goals.
  2. Global variables. Okay, so they're not exactly global but there were a number of variables declared outside of the game functions because they were referenced by multiple of them. In some cases, this was unnecessary. Whenever possible, I replaced the code which referenced the variable in global scope with more "correct" code. Consider the following example:
function update() {

    if (ball.body.velocity.x === 0 && ball.body.velocity.y === 0) {
        anim.stop();
    } else {
        var speed = Math.min(1, Math.max(Math.abs(ball.body.velocity.x),
              Math.abs(ball.body.velocity.y)) / 200) * 9;
        if (anim.isPlaying) {
            anim.speed = speed;
        } else {
            anim.play(speed, true);
        }
    }

    // ... other update stuff ...

}
Here, the variable anim was a global reference to the ball's single animation object. The ball variable is already global, so keeping the anim variable around seemed redundant.
function update() {

    if (ball.body.velocity.x === 0 && ball.body.velocity.y === 0) {
        ball.animations.stop();
    } else {
        var speed = Math.min(1, Math.max(Math.abs(ball.body.velocity.x),
                Math.abs(ball.body.velocity.y)) / 200) * 9;
        if (ball.animations.getAnimation("roll").isPlaying) {
            ball.animations.getAnimation("roll").speed = speed;
        } else {
            ball.animations.play("roll", speed, true);
        }
    }

    // ... other update stuff ...

}
The code above is better because it accesses the ball's roll animation via the provided Phaser animation functions. It's also more clear when looking at the code that this section is dealing with ball animation. Who was to know what anim referred to before? 
  1. Timers. Ugh. This one was terrible. When the ball was tossed back in from being out-of-bounds, I had a timer to determine when "regular" play should start again. I had it figured out how long it would take for the ball to re-enter the play area based on its location and speed - and I hard-coded a timer based on that. Well, that was ugly and wrong. When playing on my phone, which ran just a little bit slower, the ball wasn't back in-bounds before play restarted, which immediately resulted in the ball being declared out-of-bounds again. Endless toss-ins ensued. And I knew when I did it originally that it was a hack, but I did it anyway. Shame on me. But I fixed it now, along with the next issue...
  2. Proper encapsulation. Sure, this is functional programming, not OO. But since the ball object couldn't make the out-of-bounds determination itself, fixing the issue of the toss-in timer would have required more duplication of code. Instead, I took the bounds check logic and put it in the ball itself. Now the update function can ask the ball if it is in or out of bounds and, depending on which play mode we're in, decide what to do.
ball.inPlay = function() {
    return (this.position.x > 40 && this.position.y > 30
            && this.position.x < 1640 && this.position.y < 800);
};

function update() {

    // ... other update stuff ...

    if (mode === PLAY_MODE && !ball.inPlay()) {

        // changes mode to TOSS_MODE and then to READY_MODE
        tossBall(ball.position.x, ball.position.y);

    } else if (mode === READY_MODE && ball.inPlay()) {

        mode = PLAY_MODE;

    }

}

I feel much better about the Frog Soccer code now, and anyone who happens to examine it on GitHub might think I'm a little less of a hack. Just a little less. I'm better than the frogs in today's comic.

Amphibian.com comic for 24 August 2015

Friday, August 21, 2015

Using Touch with Phaser

My goal for Amphibian.com was to develop it as a mobile-first webcomic. That's why it reads vertically and uses SVGs for graphics that stretch and shrink to any size. A year's worth of client browser stats, however, informs me that mobile users are still in the minority on the site. Nonetheless, I still want to make sure everything on there works on phones and tablets.

That includes my 404-page frog soccer game.

Up until now, I've been developing it as a way to learn how to use Phaser for game development and have been focused on the basics. It was more common to take input from the keyboard in the examples so that's all I've been doing. But today I found it was very easy to add touch controls - at least in my game.

There are two places where the keyboard is used in my game.
  1. Hit the space bar to start playing
  2. The arrow keys move the frog
Starting the game with either the spacebar or a tap (or mouse click) was simple:

function update() {

    // ... other update stuff ...

    if (mode === WAIT_MODE && (spacebar.isDown || game.input.activePointer.isDown)) {
        mode = PLAY_MODE;
    }

    // ... other update stuff ...

}

In Phaser, game.input.activePointer normalizes input from the touchscreen and the mouse, and its isDown property is an easy way to check if any button has been clicked or the screen has been touched in any way. If you wanted to get more specific with mouse input, there are other properties that represent the individual buttons. With touch input, you have the option of reading location data from multiple pointers as a way of supporting multitouch, but none of that was necessary for my game. I just want to know that you've touched or clicked to start the play.

The other type of input, from the arrow keys, seemed like it might be more difficult to reproduce with touch input. Not at all! I was impressed with how simple it was to direct the frog based on touching the screen.

function update() {

    // ... other update stuff ...

    if (mode === PLAY_MODE) {

        if (game.input.activePointer.isDown) {
            game.physics.arcade.moveToPointer(frog, 180);
        }

    }

    // ... other update stuff ...

}

Basically, the code above just checks to see if the user is touching the screen or holding down a mouse button. If they are, the frog is directed towards wherever the pointer is located. For mouse input, that's the cursor location. For touch input, it's the location of your finger. Couldn't be easier!

With just these few lines of code I was able to touch-enable my game. I'm still struggling with the canvas size and page navigation on mobile, but it is playable. Give it a try: http://amphibian.com/404/. Don't forget that you can see the complete source code on GitHub!

After playing a few rounds, make sure you read today's comic as well.

Wednesday, August 19, 2015

Loop or Map?

If I use map, can I fold it
back up when I'm done?
Here's something that has been coming up a lot lately: when processing an Array in JavaScript, should I use a for loop or the map function?

If you've looked at my code you'll notice a distinct lack of map. I don't use it very much. I honestly don't think I do a lot of Array iteration in general, but when I do, I typically just write a for loop. Good? Bad? Does it matter?

Let's look at a typical scenario in my comic code...taking an array of results from a database query and turning them into an array of data to return.

pool.query('SELECT filename, type FROM comic_img', function(err, rows) {

    var data = [];

    if (rows.length > 0) {
        for (var i = 0; i < rows.length; i++) {
            data.push({
                name: rows[i].filename,
                mimeType: rows[i].type
            });
        }
    }

}

That's the method using a for loop. Pretty straightforward. Make an empty array for the return data, loop over the rows of the query results, pushing new objects to the data array that are made from parts of the objects in the rows array.

Now let's do the same thing with the map function.

pool.query('SELECT filename, type FROM comic_img', function(err, rows) {

    var data = rows.map(function(val) {
        return {
            name: val.filename,
            mimeType: val.type
        };
    });

}

It's a little more compact, without the need for the definition and incrementation of i, comparison with rows.length, or access to the object by index. You could argue that the map version is more readable, which is nice. I do like my code to be very readable.

What you can't say is that the map version is any faster. Internally, map has to be doing a loop plus other stuff, which will undoubtedly make it slightly less performant than the basic for loop. The speed difference won't be that much different, so in most cases you shouldn't be too concerned.

There is another benefit to the map coding style. When you already have your code structured this way, it's easy to add asynchronicity. What if you just want the array processed but don't care about the order? Remember when I talked about the Node async module? It's simple to turn the plain map code into asynchronous map code:

var async = require('async');

var rows = getSomeArray();

async.map(rows, function(val, callback) {
    callback(null, {
        name: val.filename,
        mimeType: val.type
    });
}, function(err, data) {
    console.log(data);
    // do whatever you want with the resulting data
});

Instead of the processing function returning the new data, it passes it as the second argument (first would be any error that occurred) to its supplied callback function. And instead of having map return the new array, async has you specify a third argument which is a callback function. When everything is done, it gets called with the results. Sure, in this example there's not really any point to making the processing asynchronous, but if your processing involves anything with the file system or a web service call you have a perfect candidate.

That would be a lot more difficult to do with a for loop. You'd actually need several for loops. And probably some recursion. And magic. Just forget about it.

The moral of the story is, map is probably better in most cases than for loops. It's more readable and gives you a good foundation for expansion in the future. I'll try to do better at it myself. I'll also try to make better comics, but for today this is all you get:

Amphibian.com comic for 19 August 2015

Monday, August 17, 2015

Frog Animations with Phaser

I'm still putting the finishing touches on my 404-page Frog Soccer game. One of the things that I've been putting off is doing the animations for the frogs themselves. I didn't think the code changes would be that difficult, but drawing the frogs in all those positions could be very time consuming. I didn't already have images for the frog jumping toward the viewer and away from the viewer, but now I do. Three hours later...


Anyway, once I had these awesome sprite sheets of frogs jumping in every possible direction, it was time to use them with Phaser. Setting up sprite sheets in the preload function is easy.

function preload() {

    // ... load other stuff ...

    // spritesheets for frog animation
    game.load.spritesheet("frog", "images/frog_ani.png", 79, 60);
    game.load.spritesheet("frog2", "images/frog_ani2.png", 79, 60);

    // ... load some more stuff ...

}

The last parameters to the function calls are the width and height of each image in the sheet. The images actually contain four rows of three frames each, each 79x60, while the overall image size is 237x240. Phaser will break it up for me into individual frames that I can reference in the code.

Also note that I have two separate sheets. In one all the frogs are green and in the other they are all orange. This is another change I am making so it's easier to tell which frog is yours while playing. It could get confusing sometimes.

Now I can add the animations in the create function.

function create() {

    // ... do other create stuff ...

    frog = group.create(940, 400, "frog");
    // ... other frog setup here ...
        
    frog.animations.add("left", [0, 1, 2], 10, true);
    frog.animations.add("right", [3, 4, 5], 10, true);
    frog.animations.add("front", [6, 7, 8], 10, true);
    frog.animations.add("back", [9, 10, 11], 10, true);
    frog.animations.currentAnim = frog.animations.getAnimation("left");
        
    otherFrog = group.create(720, 400, "frog2");
    // ... other otherFrog setup here ...

    otherFrog.animations.add("left", [0, 1, 2], 8, true);
    otherFrog.animations.add("right", [3, 4, 5], 8, true);
    otherFrog.animations.add("front", [6, 7, 8], 8, true);
    otherFrog.animations.add("back", [9, 10, 11], 8, true);
    otherFrog.animations.currentAnim = otherFrog.animations.getAnimation("right");

    // ... more create stuff ...

}

For each color frog, I create four animations. Each row of images in my sprite sheets represents the three frames of a frog jumping while facing a particular direction. The left-jumping frames are in the top row, positions 0, 1, and 2. The right-jumping frames are in the second row, positions 3, 4, and 5. And so on. You get the idea. When adding the animations, the array specifying which frames make up your animation is the second parameter. If your sprite sheet ran up-and-down instead of left-to-right like mine does, you'd just use a different set of numbers. It's flexible. The particular frames that make up a single animation could be mixed up all over the place in your sprite sheet - that would be confusing but you could handle it just by listing them all in the array.

The third parameter is the animation speed in frames-per-second. I am making the opponent a little slower than you in the game, so I use a slightly slower animation speed. The fourth parameter, which I set to true, is whether or not the animation should loop.

Also note that immediately after creating the animations, I set currentAnim to a specific one. If I don't do this, the animation starts out with whatever one was the last created. That could mean my frogs would have their backs to me instead of facing the ball!

Making a particular animation loop play is easy. I could just call frog.animations.play("left") to play the left-jumping loop, for example. It would place until I call frog.animations.stop(). But of course I want the animation to match the direction in which the frog is actually travelling!

The first thought is to set the animation based on which arrow key the user is holding down. That works, but can get tricky. For example, what if both the up and left keys are being held down? Down and right? Down and left? There are a lot of potential combinations and the logic gets deep. And there's one other consideration - the opponent frogs needs animation set and I definitely can't use the arrow keys for that one.

The solution I came up with was to create a function that I could call from within update and pass both frogs as parameters. Using the physics velocity of the frog, I decide if animation should be completely stopped, or which set to play. If the frog is moving diagonally, it will set based on which cardinal direction has the higher velocity.

function update() {

    // ... lots of other stuff ...

    setAnimation(frog);
    setAnimation(otherFrog);

    // ... still more stuff ...

}

function setAnimation(f) {

    if (f.body.velocity.x == 0 && f.body.velocity.y == 0) {

        f.animations.stop(null, true);

    } else {

        if (Math.abs(f.body.velocity.x) >= Math.abs(f.body.velocity.y)) {

            if (f.body.velocity.x > 0) {
                f.animations.play("right");
            } else if (f.body.velocity.x < 0) {
                f.animations.play("left");
            }

        } else {

            if (f.body.velocity.y > 0) {
                f.animations.play("front");
            } else if (f.body.velocity.y < 0) {
                f.animations.play("back");
            }

        }

    }

}

One thing to note about the animations.stop(null, true) function above - the first parameter, where I send null,represents the name of the animation to stop. It is supposed to be optional. The second parameter indicates if the animation should reset to the first frame, and defaults to false. I wanted the frog to go back to the first frame (sitting) but I didn't need to specify an animation name - I just wanted to stop whatever might be playing. Like I said, the first parameter is supposed to be optional according to the documentation, but it didn't work for me unless I explicitly provided the null first argument. Could be a bug.

In the end, I was happy with the results. Both frogs look better jumping around instead of just gliding across the field. You'll be happy with yourself if you read today's comic...and try clicking (or tapping) on the "naked" frog in the third frame.

Amphibian.com comic for 17 August 2015

Friday, August 14, 2015

Integration of the Frog Soccer Game

After getting some testers to try out my frog soccer game (mostly children) and making a few tweaks to the physics of the frogs and the ball, I decided that it was good enough to replace the old 404 page on Amphibian.com. Not that I'm completely done with it, but it's good enough that if someone finds it I'm not too upset.

It turns out that was easier said than done.

I have been keeping the source code for the game in its own repository separate from the comic repo. I want to keep the two mostly separate so that I can update the game independently of the comic. How, then, should I go about having them combined from a user perspective when visiting the site? It might not be the best, but I came up with this plan...

First, I moved the variables that control the width and height of the game canvas out of the game2.js file. I put them inside a script tag in the index.html.

<!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

    <title>Froggy 404</title>

    <link rel="stylesheet" type="text/css" href="css/style.css"/>

    <script>
    
    var width = window.innerWidth;
    var height = window.innerHeight;

    </script>
    <script src="//ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js"></script>
    <script src="js/phaser.min.js"></script>
    <script src="js/game2.js"></script>
    
</head>
<body>

<p>This is the 404 Page for Amphibian.com</p>

<div id="gameArea"></div>

<p>Thanks for playing!</p>
  
</body>
</html>

As you can see, I also added a div with the id "gameArea" to the HTML so that I can explicitly place the canvas when the Phaser Game object is created.

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

I made these changes so that I could include the game2.js file from a totally different HTML page and the game will still work.

The next step was to create a symbolic link in the main directory of the comic to the public directory of the 404-page game. I keep clones of both repositories under the /projects directory on my Ubuntu Linux server.
$ cd /projects/comic
$ ln -s soccer /projects/comic-404/public
Now my comic app can peer into the public folder of the 404-page app using the alias "soccer." This allows me access to the JavaScript, audio, and images as if they were part of the comic without them actually being part of the comic. I also added /soccer to the .gitignore file in the comic's main directory - so git doesn't think soccer is actually part of this repo.

Now I changed the code for the comic app. I set up a special route for the game under the path /404. If http://amphibian.com/404/ is requested, I respond with a special Jade template named "missing." Any requests for other files under that path, such as http://amphibian.com/404/js/game2.js for example, will be served as static content out of the "soccer" path on disk - which is the symbolic link to the public directory of the game's repository.

var soccerRoutes = express.Router();

soccerRoutes.get("/", function(req, res, next) {

    res.render("missing", {
        title: "404 Frog Soccer"
    });

});

soccerRoutes.use(express.static("soccer"));

app.use("/404", soccerRoutes);

The "missing" template has the same style, header, and footer as the rest of Amphibian.com but also includes the "gameArea" div and sets the width and height just like the index.html file in the 404 app does. Now the code in game2.js doesn't care which page is actually including it and works both ways! I can continue to update both apps independently as well. Go to http://amphibian.com/404/ to see it for yourself.

That was my solution. It works well enough, but if you have any better suggestions please leave them in the comments below! Thanks, and don't forget to read today's comic. You won't want to hit the Undo button!

Amphibian.com comic for 14 August 2015