Wednesday, March 30, 2016

Dependency Cost

Over the weekend I was alerted to a bug in the Amphibian.com web application by a reader. For him, the "previous" and "next" navigation links would not work. Clicking on them put the page into endless "Grabbing Frogs" mode and never displayed another comic.

Fortunately, the issue was not difficult to correct. Since Amphibian.com is (almost) a single-page-application, each time a new comic replaces the currently visible one I have to generate a new Pinterest button for the correct comic. Yeah, you're probably wondering, "why a Pinterest button?" I don't know. It seemed like a good idea at the time...

I'm generating the new button by calling a slightly undocumented function in the Pinterest code. I don't think they intended for it to be used on pages quite like mine. The problem arises when the function is unavailable. Maybe Pinterest is blocked. Maybe Pinterest is down. Maybe certain browsers actually download an older version of the code where that function doesn't exist. Doesn't matter why - the end result is the same. Without that function, an error occurs in my JavaScript and the new comic is never displayed. I fixed this issue and then immediately found another similar issue with my call to Emoji One's JavaScript. Fixed that too.

This got me thinking about what I'll call Dependency Cost. I didn't really think about the cost of my code being dependent on Pinterest and Emoji One behaving in a certain way. I don't control either of them, and they could change or vanish at any time - resulting in my comic readers getting shut out of my site. When you think about it, this is really an unacceptable situation. But how many situations like this are you in right now with your code? I think we're all in too many. Take the setup Amphibian.com for example - it's built on Node using Express and over a dozen other modules all downloaded from npm at first install. What if I had to recreate the site and npm was down. Do I think npm will be around forever? Nothing lasts forever.

Just something to think about when you're building your next application. Or you can think about today's comic. That's much more fun.

Amphibian.com comic for 30 March 2016

Monday, March 28, 2016

Know Your vi

I through in a little jab at vi in the third frame of today's comic. The truth is, I actually use vi almost every day at work. Remote displays are such a hassle. It got me thinking about this nice vi cheat sheet I was given on my first day of work (almost 15 years ago).

It hung on the wall of my cubicle all these years. I found a copy of it on the Internet and wanted to share it with you!

There are a couple of cleaned-up versions of this same style sheet floating around. I like it because it spells out "vi" with the commands. Just in case you forget what the commands are for. Mine is a copy of a copy of a copy and has some hand-written notes on it too, just like the one I found above. Gives it character.

Right after you read today's comic, go log on to a Linux terminal and edit something with vi!

Amphibian.com comic for 28 March 2016

Friday, March 25, 2016

Easter Eggs

While today's comic is about Easter eggs (maybe?) the comic itself does not contain any. And by that I mean it doesn't have any fun undocumented features. It might have real eggs. Who knows?

The term "Easter Egg" for an undocumented message, joke, or feature in a software product comes from the concept of the Easter Egg Hunt where children search for brightly colored eggs containing prizes. Similarly, if you find the hidden commands or whatever to unlock the Easter Egg in a software application, you get the prize. The hiding of Easter Eggs inside software dates back an Atari game from the late 1979 when the uncredited developer hid his name inside the game. It was supposedly given the name "Easter Egg" by Atari personnel after its discovery.

If I'd had more time, I would have put one in the comic today. But, alas, my life is a bit of a disaster lately and I'm not even sure what day it is most of the time. I just got back from my second business trip in 3 weeks and I have a list of over 10,000 things to do before the end of the month. Okay, I'm exaggerating a little. The list is really only 9,875 things.

The closest thing that Amphibian.com has to an Easter Egg is the teapot response. If you go to https://amphibian.com/teapot you will get a message indicating that your tea is ready. But if you look at the HTTP response code, it's actually in the error range - specifically a 418. That's the response to indicate "I'm a teapot" in the Hyper Text Coffee Pot Protocol. I may expand on this someday.



It's not quite an Easter Egg, but there's also a way on the site to force an error condition for test purposes. It lets you see a 2-frame comic which is my lame attempt to tell you that there's been a server-side failure. You will hopefully never see it except by going to https://amphibian.com/broken.

So enjoy today's comic about eggs and Easter but not really Easter but definitely eggs. Yeah.

Amphibian.com comic for 25 March 2016

Wednesday, March 23, 2016

Perspective Transformations in Inkscape

I still haven't gotten a chance to go back to work on one of my games. I'm on another trip for work this week. But I did learn something new related to today's comic.

While it doesn't have any special features, it does have a piece of paper on the ground with writing on it. The writing is skewed to show perspective. This is something that I hadn't been able to figure out before today - how to make a perspective transformation in Inkscape.

Here's how to do it. First, get whatever object you want to transform. It can be text or a picture of something, but you have to turn it into a path first. You can do that by using the Path - Object to Path menu option.

In this example, I'll transform one of my frog images. It is made up of lots of paths, all in a group. That's ok. To perform the skew, draw another path around the object in the shape that you want it to look like in the end. Start in the lower left corner and draw the line clockwise.


After you have the shape outlined by the new path, select the shape to be transformed first and the path second (Shift+click). Then use the menu option Extensions - Modify Path - Perspective. It takes a few seconds, but should look like this after it runs.
You can delete the outline path if you want.
That's how I made the text on the "landing page" look like it does. I'm always happy when I learn something new. I'm also happy when you read my frog comics.

Amphibian.com comic for 23 March 2016

Monday, March 21, 2016

Amphibian.com's got Web Sockets

Today's comic might look like a simple joke about planting light bulbs, but it is really so much more. Well, actually it's only a little bit more. But still more.

The lamp post in the third frame can be turned on and off by clicking on it. But it doesn't just go on and off for you the clicker; it goes on and off for everyone looking at the comic. Try it. Go to Amphibian.com and look at the lamp. Call a friend on the other side of the world and have them also go to Amphibian.com and look at the lamp. Click on the lamp. You'll both see it toggle state at the same time.

I finally got around to integrating Web Sockets via Socket.io into the site. The state of the lamp is stored on the server and clicks emit "lamp-toggle" events from the clients. When a toggle event is received on the server, the state of the lamp switches and the new state (on or off) is broadcast out to all the clients. The clients show or hide the "glow" effect accordingly.

Server Code:

var lampOn = true;

io.on("connection", function (socket) {

    socket.on("lamp-toggle", function(data) {

        if (lampOn) {
            io.emit("lamp-off");
        } else {
            io.emit("lamp-on");
        }

        lampOn = !lampOn;

    });

});

Client Code:

var socket = io("http://amphibian.com");

socket.on("lamp-off", function(d) { 
    $("#glow").hide();
});

socket.on("lamp-on", function(d) {
    $("#glow").show();
});

$("#lamp").click(function() {
    socket.emit("lamp-toggle");
});

On the server side, I had a little trouble with the fact that I have Node HTTP servers for both secure and insecure web traffic in the application. I wanted the same Socket.io instance to service both. Fortunately, it is easy to attach a Socket.io server to multiple HTTP servers. In the code snippet below, I call attach on an existing Socket.io instance to bind it to a second HTTP server (line 17).

var app = express();

var server = http.createServer(app).listen(3000, function() {
    console.log('listening on port %d', server.address().port);
});

// create a Socket.io server attached to the HTTP server just created
var io = require('socket.io')(server);

if (ssl) {

    var secureServer = https.createServer(sslOptions, app).listen(4443, function() {
        console.log('listening securely on port %d', secureServer.address().port);
    });

    // attach the Socket.io server to the secure HTTP server as well
    io.attach(secureServer);

}

Back in the client, I just had to be smart about which URL to connect to. I never got Web Sockets to work correctly with Nginx, so I'm just bypassing it when I make the connections back from the client. Nginx listens on ports 80 and 443 and proxies HTTP traffic to the Node application which actually listens on ports 3000 and 4443. When I set up Socket.io in the client, I use these ports directly. Browsers still allow Web Socket connections to different ports on the same server without raising cross-site scripting concerns. But you can't mix insecure HTTP and secure Web Sockets (or vice versa). Look at this update to the client code from above, where I examine the browser's location to determine what URL I should use for connecting:

var urlParts = window.location.href.split("/");
var cUrl = urlParts[0] + "//" + urlParts[2];
if (!window.location.port) {
    if (urlParts[0] !== "https:") {
        cUrl += ':3000';
    } else {
        cUrl += ':4443';
    }
}

var socket = io(cUrl);

// ... rest of client code from above ...

So go play around with that lamp! And feel free to read more comics while you're there.

Amphibian.com comic for 21 March 2016

Friday, March 18, 2016

Pseudocode

You may have heard stories of brilliant software engineers jotting down code on bar napkins when they have a sudden epiphany while drinking with their friends. Maybe you've done this sort of thing yourself. Maybe, like the frogs in today's comic, you've written down code in a stranger place.

I've never written code with letter-shaped pasta, but I have written out lots of algorithms on paper beside my keyboard. It's never in perfect form for compilation, but is usually just pseudocode. I am not a genius when it comes to algorithms; I can rarely go straight from my brain to they keyboard and have the code work on the first (or fifty-first) try. When I was working on the match-3 game back in January, it took lots of scratch paper pseudocode to get things working correctly.

For whatever reason, writing out the algorithm in pencil and then working through it on paper really works for me. I usually write a list of the variables off to the side, along with their current values as I work through the steps. I erase and re-write the value of each variable as it changes. This is a skill I was taught in college, using a whiteboard instead of paper, but it works just as well.

If you haven't done something similar yourself, give it a try next time you're stumped on an algorithm problem. Or just take a break from programming and read some of my comics!

Amphibian.com comic for 18 March 2016

Wednesday, March 16, 2016

I Don't Like Gingerbread

I have noticed that it's been over 2 weeks since I worked on my platformer. I haven't abandoned it, but I have taken a break from it to work on other things. A trip to Texas where I got sick and this stupid Daylight Savings Time thing messing up my sleep schedule haven't helped.

This basically means that I don't have any code or Phaser insights to share at the moment. I honestly don't have much of anything to share, other than comics and the fact that I don't like gingerbread.

But today's comic has a gingerbread house! Well, technically it's a gingerbread grocery store, but the fact remains that I don't like gingerbread. When we make "gingerbread" houses around here at Christmastime, we use graham crackers which I consider to be more edible.

Why am I writing about this? I have no idea.

Amphibian.com comic for 16 March 2016

Monday, March 14, 2016

Tags are Live, and a New Server

After getting home from Texas Saturday evening and despite still having a bit of a cold, I managed to get all the code merged and deployed for the comic tags. New and recent comics will have a set of tags displayed below them, listing the characters and themes in each comic. Clicking on one of the tags will take you to a page showing all comics with that tag. So if Business Frog is your favorite, you can easily find all the comics with him in them, for example.

Unfortunately this means I have to go back through over 250 comics and tag them all. That process might take me a few days, so you won't find tags on the older comics right now. I'll get to them, though, don't worry.

In other news, I also added a dedicated database server to my set of virtual machines hosted by Digital Ocean. This takes a bit of load off the web server and the comics are actually more responsive now. If you're a regular visitor you might notice the speed improvement.

But now the most important thing - pictures of my daughter's stuffed frog from from the trip last week!

In the airport early Monday morning.
Coffee and a cheese danish in Texas.
Just hanging out in the hotel.
Watch out for falling ice!
I had a cold, so Froggy gave me some medicine.
The view at night from our hotel.
Taking a walk in Prairie Creek Park.
A nice pedestrian bridge over Prairie Creek.
Enjoying some pizza the night before we left.
Long layover in Detroit, but they have a cool glowing tunnel.
If you've made it this far, why not click the link below and read today's comic?

Amphibian.com comic for 14 March 2016

Friday, March 11, 2016

A Rain Effect Using Only CSS

Today's comic contains something that I've never used before in a comic - CSS3 Animation. The rain effect in the first 3 frames is done purely with CSS! Here's how it works.

All the raindrops in each frame are just DIVs with a color gradient background.

<div class="drop></div>

The CSS style for a drop contains a special property, animation. The browser-specific versions, -webkit-animation and -moz-animation, are also specified to catch older browsers.

.drop {
    -webkit-animation: fall .68s linear infinite;
    -moz-animation: fall .68s linear infinite;
    animation: fall .68s linear infinite;
}

The format of the animation property's value is: <name> <duration> <timing function> <iterations>.

The name of the animation is whatever you want. Mine is called "fall" because that's what raindrops do. I specified a duration of 0.68 seconds, because I played around with it and just liked that duration the best. The timing function here is linear. That means there is no easing of any kind; the drops always move at a constant speed. Finally, I specified "infinite" for the number of iterations. The reasons for these values should make sense shortly...

I gave my animation a name, but I also need to specify what an animation with that name actually does. To do that, you use another CSS directive called @keyframes. (you can also use @-webkey-keyframes and @-moz-keyframes for older browser support)

@-webkit-keyframes fall {
    to {margin-top:700px;}
}

@-moz-keyframes fall {
    to {margin-top:700px;}
}

@keyframes fall {
    to {margin-top:700px;}
}

Here I am specifying that an animation named fall should alter the margin-top property until it reaches a value of 700px. Once that value is reached, one iteration of the animation is considered to be finished. Since I specified infinite iterations above, it means that every time the animation ends it will just reset to the original value and run again. The time it will take to change the margin-top value from whatever it starts at to 700px will be equal to the duration specified earlier.

All I had to do was give the raindrops a random position when I created them, and by animating an increase in their top margin they appear to fall past the bottom of the frame before being reset.

The end result is the beautiful rain effect you can see by clicking the link below and reading today's comic! CSS3 animations can be an easy alternative to JavaScript based animations. They're actually very well-supported by most browsers, even IE 10.

Amphibian.com comic for 11 March 2016

Wednesday, March 9, 2016

Searching my Comic Archive

I have so many comics now (252) that finding one in the archive is getting hard, even for me. And what if you want to find all the comics that have Science Frog, or Pirate Frog? It's not easy. How many comics have embedded games? Who knows?!?

To correct this problem, I've decided to add tags to all the comics. Whenever I make a new one, I'll tag it with the characters, the theme, a special feature, or whatever else makes sense. You'll be able to see these tags at the bottom of the comic. Like all tags these days, they'll have # in front of the word. Clicking on one of the tags will take you to the archive page, filtered to just show the comics with that tag.

A test page showing my new comic #tags

I'll also be able to put a filter link directly on the Archive page, so you can find comics that contain a search term or have a common tag such as "#game" or something. These are exciting times for frog comic lovers everywhere.

Of course, these new features aren't available yet on the public version of Amphibian.com, but they will be soon. I'm still working out some things, but I'm also sitting in a hotel room in Dallas this week. I can never seem to be as productive when I'm away from home. You can still view today's comic without the tags at the bottom; just follow the link below.

Amphibian.com comic for 9 March 2016

Monday, March 7, 2016

Are There Still Tech Books?

I had to fix a dresser drawer the other day. We're using it in my newest daughter's room, but it's really old. It was actually mine when I was a kid. The track guide broke off the middle drawer because the wood was badly damaged, probably from something I did to it in my youth. Part of the repair required me to use some glue and I asked my 10-year-old daughter to bring me some books off the bookshelf to put weight on it while it dried.

The books she brought me made me wonder about technology books today. I have some old(ish) books on the shelf that I bought who-knows-when, and looking at them piled on top of an old drawer made me think about how I haven't bought a technology book in a long time. And this stack in front of me is worthless now!


ASP In a Nutshell. Almost embarrassed to admit owning this one. Printed in 1999. I had another ASP book that I got rid of a few years ago. I think I kept this one just for the snake on the cover.


The JDK 1.4 Tutorial. Really came in handy back in 2002. The best part is the woman on the front who looks like she's trying to pull off a Medieval Ewok cosplay.


Another classic from 2002, Mastering Enterprise JavaBeans gave me a lot of code that I am still maintaining today. Unfortunately.


The most modern book in this stack, Ajax in Action dates to 2006. I remember excitingly opening this one to learn about the new asynchronous method of bridging the web client and server. I ended up feeling a little bit disappointed as it didn't really tell me anything I hadn't learned on my own in the previous few months.

A quick look around Amazon.com tells me that they still do in fact publish books on software technologies. But I have to wonder who buys them, with so much information available for free on the Internet. But it's harder to glue a drawer with the Internet.

Be sure to read today's Amphibian.com comic. Since so many of them have special web-only features, they'll most likely never be published in a book. You can only read them online!

Amphibian.com comic for 7 March 2016

Friday, March 4, 2016

Beat Panels

I was going to write something about programming today, but I decided to put that off until later. Just kidding - procrastination was the subject of today's Amphibian.com comic! In reality, I never planned to write anything today.

Since I'm clearly writing something anyway, let me talk for a minute about Beat Panels. I used one today in the comic. It's the next-to-last frame, the one which contains no dialog. It's just Science Frog and CEO Frog staring at each other. Beat Panels are typically used to indicate the comedic pause before a punchline, or to indicate the quiet contemplation of the characters. I think this is the first time that I've used one.

In the case of today's comic, the pause was meant to make the reader think about the nature of time and how we perceive the present. All of our perception is the present. We can remember the past and anticipate the future, but we only experience the present. A year from now, it will be the present. A hundred years from now, it will still be the present.

The present is all we've got. Use it to read my comics.

Amphibian.com comic for 4 March 2016

Wednesday, March 2, 2016

Using "shutdown" to Save State in Phaser

Today is the comic that I've been working on in all my spare time for the past week, but have been thinking about for about a year. For such a long time, I've wanted to work a Dragon Warrior parody into a comic. That game was such a major part of my childhood. I played it for countless hours on my NES, along with its sequels.

If you're not as familiar with it as I am (my wife had never heard of it), it was the game that introduced console turn-based RPGs to the American market. You play a warrior trying to save a princess and slay a dragon by defeating various monsters to gain gold and experience. The gold gets you better armor and weapons, while the experience ups your level for more strength, magic, etc. As you walk around the world, a battle starts randomly. You and the monster take turns hitting each other until one of you dies. Assuming you win, the game returns to the map screen and you walk around some more.

If you haven't seen the comic yet, take a look at it. My parody of the game is embedded in the 3rd frame, and is completely playable.

The walking-around game state.

When I implemented this in Phaser, I made the walking-around-on-the-map one game state and the fighting-a-monster (or a printer in my case) another game state. After the fight ends, I wanted to go back to the walking-around state but put the frog at the same map position he was before the fight started - not reset everything in the state back to the default. But the way Phaser works is that when you start a game state, the create function is always called. How could I ensure that the frog ended up back where he belonged each time that happened?

The fighting state. Kick that printer!

The answer is to make use of the shutdown function on the state. I hadn't used this one before; my game state objects never defined it. But it is important if you wanted to save the current values of anything in your game before switching states, as it is called by Phaser when one state is being stopped but before another starts. I used it to save the frog's current position, which I then used the next time create was called.

Here is a sample of the code, to help in the explanation.

function walkAround() {

    // default frog's position
    var fPos = { x: 200, y: 500 };

    function create() {

        // create the frog wherever fPos says to put him
        frog = this.add.sprite(fPos.x, fPos.y, "frog", 0);

        // ... other stuff ...

    }
    
    function shutdown() {
        
        // save the frog's current position to use
        // next time create is called.
        fPos.x = frog.position.x;
        fPos.y = frog.position.y;
        
    }

    return {
        create: create,
        shutdown: shutdown
    };

}

function fight() {

    // ... all the stuff for the fighting state ...

    return {
        // an actual state object
    };

}

var s1 = walkAround();
var s2 = fight();
 
var game = new Phaser.Game(width, height, Phaser.CANVAS, "cell-2");
 
game.state.add("walking",  s1);
game.state.add("fighting", s2);

game.state.start("walking");

The fPos variable gets a default value when it is initialized. This is the value used the very first time create is called. But after shutdown is called, fPos changes. Since the state object isn't ever destroyed, fPos retains its value and the next time create is called, the frog is put in his last known location.

This technique will work for anything in your game state that you'd like to save and restore, such as when your player switches to a menu state and then returns to play.

Make sure you check out the comic and play the game! If you'd like to see the complete source code for the game (or anything else on the comic) you can find the repo on GitHub.

Amphibian.com comic for 2 March 2016