Monday, August 31, 2015

Restoring a MySQL Database

If you don't test your backup and prove that it works, you don't have a backup.

I've been backing up my Amphibian.com database for some time now, but haven't really had to restore it yet. That changed today. Thankfully, it worked.

This process started because I finally decided to get back to work on switching from MySQL to Postgres. I started this months ago but got sidetracked. To really make some progress, I wanted to set up a virtual machine that will run both the MySQL and Postgres versions of my database on Ubuntu 14. Then I can make my code changes and test against the VM until I know it's all working. I had both databases installed on a physical server in my home, but that limited me to only being able to work on it while I was at home. With a virtual server, I can run it on my laptop as well.

What does this have to do with restoring a MySQL database? I'm getting to that.

After installing VirtualBox on my laptop, installing Ubuntu 14 on a virtual machine, and installing MySQL on Ubuntu 14, it was time to test out one of my Amphibian backup files.

I make the backups using mysqldump on the "real" server (see one of my previous posts for more details):

# mysqldump amphibian > amphibian_data.dump

I copied the backup file off my server and onto my new virtual machine. Now I had a fresh install of MySQL and a .dump file of the Amphibian database. All I had to do was create the amphibian database on my new installation and have MySQL read the contents of the .dump file into it.

# mysql -uroot -p<password>

mysql> create database amphibian;
Query OK, 1 row affected (0.02 sec)

# mysql -uroot -p<password> amphibian < amphibian_data.dump

It ran for a few minutes, but when it finished I had a perfect copy of my Amphibian.com database. If I had to restore my actual server, I am now sure that it will work.

And of course, after spending all that time getting ready to work on the MySQL-to-Postgres transition, I didn't have any time left to actually work on it. But I'll be ready next time. Next time.

Amphibian.com comic for 31 August 2015

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

Wednesday, August 12, 2015

Using Facebook's Graph API to Count Shares

Have you shared today's comic yet? Getting it shared at least 100 times on Facebook is the only way to unlock the action in the last frame. Well, it also has to be Wednesday. So share it 100 times today or wait until next week to try again.
Bombs don't look like this in real life.
This depiction is illogical.

The joke is that the frogs have discovered a logic bomb in a computer, and logic bombs only go off when their criteria are met. The criteria of this particular one include Facebook shares and the day of the week. Really it's designed to get me lots of attention on social media, but there is a joke in it.

Now to the good part...how does it work? The day-of-the-week part is easy, but checking the number of Facebook shares was slightly more involved. I used the Facebook Graph API.

There is a ton of stuff you can do with it, but for now I'm keeping it simple. I wanted to be able to check how many shares a given URL has. And you ask yourself, "Why doesn't he just look at that little number down below every comic?" Well, I'll tell you. That's a Facebook widget that functions by embedding an iframe in the page. I can't really check what it's doing from my own code. I had to write some server-side code to interface directly with Facebook.

Since share information is public, you can access it just by hitting a Facebook URI with any valid access token.

https://graph.facebook.com/v2.4/?access_token=<your-token>&id=<object-id>

The object id is just the URL that you want to check shares on. For me, it's something like http://amphibian.com/205. The tricky part is getting an access token. The easiest way to do it is to create a Facebook App and use the permanent access token associated with it. Sign up as a Facebook developer, and then create a new web app. After you have a web app set up, go to the Tools & Support menu and select Access Token Tool. You should then see a pair of tokens for your app, a User Token and an App Token. The App Token is the one you want because it never expires.

DO NOT share these tokens with anyone, or put them in client-side code! DO NOT! It will give anyone permission to perform actions as your application. I put the App Token in a server-side config file that is NOT committed to source control (at least not in a public repo).

Once you have both an access token and an object id (of something that's been shared at least once), hit the URL and you should get a JSON response.

Something like this:

{
  "og_object": {
    "id": "1128024717211703",
    "description": "Amphibian.com webcomic for Monday, 10 August 2015",
    "title": "Crowdfunding",
    "type": "website",
    "updated_time": "2015-08-10T08:18:03+0000",
    "url": "http://amphibian.com/205"
  },
  "share": {
    "comment_count": 0,
    "share_count": 12
  },
  "id": "http://amphibian.com/205"
}

I just parse that response and get the number of shares. I am doing this from a Node application, and just like when I used the Imgflip API to make memes, I use the convenient request module:

app.get("/shares/:id", function(req, res, next) {

    var comic = req.params.id;
    var token = "your-token-here";

    request({
        uri : "https://graph.facebook.com/v2.4/",
        qs : {
            access_token : token,
            id : "http://amphibian.com/" + comic
        }
    }, function(error, response, body) {

        if (!error && response.statusCode == 200) {

            var data = JSON.parse(body);

            res.setHeader("Content-Type", "application/json");
            res.send({
                id : data.id,
                shares : data.share.share_count
            });

        } else {
            next(error);
        }

    });

});

Again, I must stress that this code has to be done on the server side, since you don't want to give clients access to your App Token. When the client JavaScript has to check if it's ok to set off the cartoon bomb, I access a URL on my server that essentially proxies the request to Facebook. The code example above sets up a route /shares/:id that will give the share data for any comic to a client without exposing my App Token to the world.

Not too difficult. I just hope my plan is successful and the comic gets lots of shares. Trust me, it's worth it. Go on, check it out. It's also got a Zero Wing reference in there (which you can see before it's shared).

Amphibian.com comic for 12 August 2015

Monday, August 10, 2015

Funding Along With The Crowd

In the comic today, the frogs "crowdfunded" their latest endeavor by picking the pockets of the crowd of potential investors. Crowdfunding in real life is slightly more legitimate.

I am most familiar with Kickstarter as a crowdfunding platform. I was one of the higher-tier backers of the OUYA, which was one of the most successful campaigns ever run. I gave enough that I got tickets to the party back in March of 2013. I guess maybe that's why I got my dev OUYA on time (in December 2012) and everyone else was complaining that the stores had them before the backers did. Then OUYA struggled for a while before being acquired by Razer last month. Did it ever fulfill the dreams of those of us who donated money? Can any project ever really live up to its hype?

I even tried a Kickstarter campaign myself once. OUYA was doing a promotion where if you got funded for at least $50k to make an OUYA-exclusive game, they would match what you got from Kickstarter. It sounded like good publicity, so we put up a campaign. Did it work? Absolutely not. But can I blame anyone for not donating money to me? Not really.

It did give me the idea that I should bring back my frog comics and build an audience before asking the Internet to give me money to make a game about my frog comics. So here we are. The frog comics have been running for over a year now, I'm slowing building an audience, and maybe in 10 years or so I'll have enough fans to fund my game idea at $5 each.

Today there is another crowdfunding platform called Patreon that focuses on monthly funding for art projects. It's very popular with webcomic creators, but I haven't set anything up yet. I guess I'm not sure that I qualify. Are my comics really art, since I make them in Inkscape instead of with a pen? Am I really a webcomic author, or am I just a software engineer who can make a web page resemble a comic? Maybe I just don't want to face the rejection of having no one give me any funding.

I'll keep thinking about it.

Amphibian.com comic for 10 August 2015

Friday, August 7, 2015

Custom Fonts with Phaser

It's been a while, but I'm back working on my 404-page game (full source code here) built with Phaser. I wanted to add some game text like scores and a title. Fortunately, Phaser makes this fairly simple.

Using the Phaser.Text object, you can render text to the game canvas without much difficulty.

var myScore = 0;
var opScore = 0;

var scoreText1 = game.add.text(20, 10, "Home: " + myScore);
scoreText1.fixedToCamera = true;

var scoreText2 = game.add.text(1060, 10, " Away: " + opScore);
scoreText2.fixedToCamera = true;

The code above creates two text objects that display the team scores, with the text fixed to a certain location on the screen. This means that as the camera moves around, the text won't.

Putting text on a canvas is not trival, but Phaser makes it appear as if it were. To do the magic, Phaser is actually rendering the text to a hidden canvas and using that canvas to get the bitmap image to display in your main game canvas. The catch? Any font you use has to be already loaded and ready in the browser. Not a big deal if you want plain, boring text. But I wanted to use my comic's go-to font Sniglet.

Sniglet is available free from Google Fonts, so I include it on many of my pages the typical way...

<link href='http://fonts.googleapis.com/css?family=Sniglet' rel='stylesheet' type='text/css'>

That doesn't help me in Phaser. Because the font load happens asynchronously, I need to make sure that the font is fully loaded before I try to render any text with it. That's where the Typekit Web Font Loader comes in. Co-developed by Google and Typekit, it gives developers more control over web fonts, and allows me to control the flow of the game setup based on when the font is loaded.

I was a little confused by the Google Fonts integration example provided by Phaser. This is what their example does:

// The Google WebFont Loader will look for this object,
//    so create it before loading the script.
WebFontConfig = {

    //  'active' means all requested fonts have finished loading
    //  We set a 1 second delay before calling 'createText'.
    //  For some reason if we don't the browser cannot render the text the first time it's created.
    active: function() { 
        game.time.events.add(Phaser.Timer.SECOND, createText, this);
    },

    //  The Google Fonts we want to load (specify as many as you like in the array)
    google: {
        families: ["Sniglet"]
    }

};
 
function preload() {

    // Load the Google WebFont Loader script
    game.load.script("webfont", "//ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js");

    // ... load other stuff ...

}

function createText() {

    // ... create text objects here ...

}

I don't like how Phaser's examples just throw the code out there with no explanations. What's going on is a WebFontConfig object is being created for the Web Font Loader to use when it does it's thing. In this example, two fields are specified in the object: active and google. The google field is an object that tells Web Font Loader to load the specified font families from Google Web Fonts. I am only loading one, Sniglet. The active field specifies a function that will be called when the fonts are fully loaded and ready. In Phaser's example, that function waits one second and then calls the createText function. In the game preload, the Web Font Loader script is dynamically injected into the page which kicks off the loading. When it's all done, active gets called, waits one second and calls createText. Text then appears in the game.

But hold on. Look at the comment above active. That's right out of Phaser's example. "For some reason..."???? Comments like that just feed my curiosity. Can I figure it out? Can I make it better?

Of course I tried getting rid of the one-second delay to see what would happen. What happened was that createText was called too fast (before the game's create function), and the text ended up below my ground tiles. The font was fine, but you couldn't see it. Adding the delay back in just ensured that everything else was done before the text was added on top of everything else. So their example works, but that's some weird control flow if you ask me.

I tried taking a slightly different approach. I include the Web Font Loader script explicitly in my HTML and then do the following:

var wfconfig = {

    active: function() { 
        console.log("font loaded");
        init();
    },

    google: {
        families: ['Sniglet']
    }

};

WebFont.load(wfconfig);

// ...

var init = function () {

    // ... variables declared and whatnot ...

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

    function preload() {
        // ... nothing new ...
    }

    function create() {

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

        scoreText1 = game.add.text(20, 10, "Home: " + myScore);
        scoreText1.fixedToCamera = true;

        // ... and so on, and so on ...

    }

    // ... all the other stuff

}

As soon as the page is ready, I call WebFont.load(wfconfig). Then in the active function, I make the call to set up the game. In my game's preload I don't have to do anything special, and I just create the text objects after all the other game objects to ensure that they are on top (in my game's create function). I shouldn't have to worry about whether or not the font is loaded yet because I put off starting the whole game setup process until after I was sure that it was loaded.

Seemed to work for me. I'm sharing this so that, at least for today, I have not subtracted from the sum of human knowledge. Huh? Read the comic.

Amphibian.com comic for 7 August 2015

Wednesday, August 5, 2015

CSS Grayscale Filter (not Greyscale)

Today's comic pokes a little fun at Internet Explorer. It's certainly not the first time I've done that. The comic talks about one of the most ubiquitous features of modern browsers, tabs. And while there was a time when no browsers had them, I chose IE for the comic because it got them later than anyone else. Microsoft's victory in the Great Browser Wars was a loss for the world - as all web innovation stagnated for years in a single-browser ecosystem.

The ironic thing is that the comic uses a feature that is not supported by even the latest version of Internet Explorer. No, wait. Ironic isn't the right term. What word am I looking for? Oh yeah, expected. The expected thing is that the comic uses a feature not supported by IE. Because it never seems to support anything, even today!

Alright, enough of the IE-bashing. The feature I'm talking about is CSS Filters. Microsoft used to support a propriety version of most of them, so at least developers had an option to make pages look similar in all browsers, but they removed that support in IE9. Even 11 doesn't support Filters yet, although it looks like it might soon. But it should, because filters are great.

The same page in Chrome 44 (left) and Internet Explorer 11 (right)
The filter I used today was grayscale. Why not greyscale? I don't know, what's up with the whole gray/grey thing? Maybe I'll talk about that some other time...

I wanted to show a comic cell that was the imagination of something in the past. Even though the date was only 2003, everyone knows that the past is always in black-and-white. So I used the grayscale filter to get rid of 80% of the color.

<div id="cell-2" style="-webkit-filter: grayscale(80%); filter: grayscale(80%);">

    <!-- comic cell contents here -->

</div>

It's really simple to use. Just specify a percentage of how much grayscaling you want. 100% will mean absolutely no colors. I left 20% of the color there and I liked how it looked. It's not 1950's black-and-white, but it still makes you think of the past. Note how I did it on the container DIV and all elements inside of it were in grayscale. It works on all elements, not just images.

I have to use the -webkit-filter and filter both because only Firefox currently supports the standard version. Still, better than IE where I get nothing. In the past I've avoided including things like this in the comics. If I couldn't make it happen in the modern version of all the major browsers I wouldn't do it. But I felt that in this case, the missing feature doesn't detract much or ruin the joke - so I went ahead with it.

Some other filters that I've wanted to use are invert and blur, but they were going to be more integral to the joke and without IE support I didn't do it. IE is limiting my creativity!

So enjoy today's comic - preferably not in Internet Explorer.

Amphibian.com comic for 5 August 2015

Monday, August 3, 2015

One Year of Comics

The first comic
It's hard to believe, but I've been publishing Amphibian.com comics three times per week for a whole year now. A whole year! That's like 156 comics! And I'm not finished!

I thought I'd take a few minutes to reflect on the things that have happened in the past year.

I also wrote 156 blog posts. One for each comic. Sometimes technical (related to something with Node or JavaScript in general, mostly) and sometimes they were not. My blog traffic went from around 20-30 views per week to around 800-900.

First daughter added this year
#ggo15
I made over 200 commits to open source projects on GitHub. Most were to my own repositories, but I am committed to keeping the source code to my comic framework open. I want to share all the code!

Some of those commits were to a fork of a game while I was competing in the GitHub Game Off 2015. And I won! I got lots of stickers, a GitHub hoodie, and my kids all got Octocat shirts.

I adopted a wonderful teenager from the foster care system. I encourage everyone to consider doing the same.

Second daughter added this year
While making a joke about paywalls, I created the best Bitcoin micropayment integration the world has ever seen. In the process, I created a legitimate use of the (yet unofficial) 402 HTTP response code. I didn't realize that at the time. I thought I was just doing a fun comic and I might make a few dollars. But Reddit went crazy for it and I got a lot of attention - and Bitcoins.

I have some now
A few weeks after that, my wife gave birth to our fourth child. I named her Kayci and I now have daughters aged 16, 10, 6, and 0.15 years.

What will happen over the next 12 months? I'm not sure. I don't really have anything planned (besides making more comics), so I'll just see where life takes me.

Take note that today's comic takes place in the same scene as the first comic did. I think that's where the frogs have all their important meetings.

Amphibian.com comic for 3 August 2015