Wednesday, August 8, 2018

Minor Comic Style Improvements

I've made a few minor adjustments to the comic's style coinciding with the restart. You might not notice unless you have a keen eye for detail.

Font Upgrades


First, I've set a specific font for the free-text in comic frames. The speech bubbles have always used Sniglet, but any text that just floated there was actually set to Verdana with a fallback to sans serif. Sure, it looked fine for Windows users and didn't look too bad when I viewed them on Linux, but sometimes I'd be on a weird browser and get a weird font that looked...weird. I don't know why I never fixed this in the first three years of the comic, but when I set my mind on it I had a lot of trouble picking a free font that I liked. I ended up going with Ubuntu. Now the text should look consistent for all browsers on all operating systems.

Here's a sample of a comic in the original font:

And here's that same comic using the new font:

The difference is subtle, but I think it's important. I'm much happier with the new font.

In addition that font fix, I've added another font option for comics. Anything that's supposed to look hand-written will now use the Architect's Daughter font. It's clean and easy to read but also warm.

Here's an old comic with writing on the whiteboard:

And here's that same comic, updated for the new font:

Mobile Theme Color


Mobile users may also notice another minor change that I've made. I set a "theme color" so the address bar will be green. Oddly enough, this is done via meta tags instead of CSS like I'd expected.

<meta name="theme-color" content="#006600">

Here's what it looks like for me, in Chrome for Android:



More to Come

That's all for now, but there are more updates coming along with the new comics. Here's this week's:

Amphibian.com comic for 8 August 2018





Wednesday, August 1, 2018

Where Have I Been?

It's been a while. I wrote my last blog post over a year ago, and the comics stopped shorty after the blogs. Some people emailed me to make sure I was okay, since there was no notice or anything. Stuff just stopped. So what happened?

Lots of stuff. Life is complicated. My life is extra complicated.

My wife and I are foster parents. We have three of our own children and at any time we could have any number of additional children. In March of 2017, while I was out of town for business, we were given a 3-month-old foster baby. We already had a toddler only 21 months old. It was just too much. I didn't have time to make comics anymore. I didn't have time to sleep anymore. I burned through my buffer of comics. I found some time to finish a bunch of drafts that I'd started, but I was unable to start anything new and in August of 2017 they just ran out.

I didn't make an announcement or anything because I didn't know what to say. Was it only temporary? Was it the end? I didn't know.

And then things continued to get harder. In October, was got an additional foster child - the baby's 10-year-old sister. I was pretty sure I'd never write another comic again.

Until the spring of 2018. It turns out that babies grow into toddlers. They start sleeping through the night. I guess I should have remembered this fact about babies, but I was really really tired. I'm not saying that anything around here is easy, but I am somehow able to write comics again.

A few of them anyway.

I'm going to start slow. There's only going to be one new comic per week, on Wednesdays. And I don't know if I'll embed any games or anything in them for a while yet. But hey, I've got something. We'll see how it goes.

Here it is, the link to the comic you've all been waiting for!

Amphibian.com comic for 1 August 2018


Sunday, April 30, 2017

New Webcomic Ad

It's been a long time, but I've started advertising Amphibian.com on another webcomic list site. Actually, The Webcomic List site. After successfully getting my comic to show up as updating properly on that site after all these years, I decided to try their sponsorship deal where you can get your comic's little square icon in the banner for a month. I'd been seeing pretty good traffic from that list already just from fixing the update status, so we'll see how this goes.

Monday, May 16, 2016

CSS3 Smoke Animation Effect

The comic today uses quite a bit of CSS3 animation. This is a rather new thing for me - I've been using mostly JavaScript-powered animations on Amphibian.com since it started. But after I did the rain animation using CSS back in March (see the comic here), I've been warming up to the idea of more CSS and less JavaScript to move things around.

For this task, I wanted to make some animated smoke come out of the frogs' rocket ship before the launch. My style is mostly just simple geometric shapes arranged to look like things, so using circular DIV elements to look like puffs of smoke was fine with me. I found a great starting point by Andrea Verlicchi on CodePen, and then modified it for my comic.

Here's the basic idea - puffs of smoke emanate from a given source element. They move downward and off to the side while fading away.

The puffs of smoke will be represented by rounded SPAN elements, with this CSS applied to them:

span.smokepuff {
    display: block;
    position: absolute;
    bottom: -35px;
    left: 50%;
    margin-left: -20px;
    height: 0px;
    width: 0px;
    border: 35px solid #4b4b4b;
    border-radius: 35px;
    left: -14px;
    opacity: 0;
    transform: scale(0.2);
}

The above styling just makes them round, grey, and positioned absolutely in their container. I also have two animation keyframes defined, one for the down-and-left movement and one for the down-and-right movement:

@keyframes smokeL {
    0% {
        transform: scale(0.2) translate(0, 0);
    }
    10% {
        opacity: 1;
        transform: scale(0.2) translate(0, 5px);
    }
    100% {
        opacity: 0;
        transform: scale(1) translate(-50px, 80px);
    }
}

@keyframes smokeR {
    0% {
        transform: scale(0.2) translate(0, 0);
    }
    10% {
        opacity: 1;
        transform: scale(0.2) translate(0, 5px);
    }
    100% {
        opacity: 0;
        transform: scale(1) translate(50px, 80px);
    }
}

The above keyframe definitions define an animation that will move the smoke puffs lower by 80 pixels and 50 pixels to either side while at the same time scaling them up and fading them out. It defines 3 steps: 0% (the start), 10% (moved a little down), and 100% (moved completely down and over). There's one for the left, smokeL, and one for the right, smokeR.

Note: if you care about being compatible with slightly older browsers, you would want copies of these with @-moz-keyframes and @-webkit-keyframes as the names as well as adding -moz-transform and -webkit-transform to them all! I left that out here to keep the example simpler!

I said this was pure CSS3 animation, but there's still a little JavaScript involved. It doesn't really do the animating, but I use some code to generate the puffs in the first place. Something like this:

function createSmoke(time, num) {

    var timeGap = (time / num); 

    for( var i = 0; i < num; i++) {

        var delay = (timeGap * i) + 's';

        var aniName = "smokeL";
        if (((i+1) % 2) == 0) {
            aniName = "smokeR";
        }

        var aniStyle = "animation: " + aniName + " " + duration + " " + delay + " infinite";
        $('#smoker').append('<span class="smokepuff" style="' + aniStyle + '"></span>');

    }

}

When this function is called, you give it the length of the animation and the number of puffs of smoke you want. It figures out how much of a delay there should be between each puff's animation starting based on those two values. For example, if you want the animation to run 5 seconds and have 10 puffs of smoke, the first puff would have no delay, the second would have a delay of ( 5 / 10 ) * 1, the third a delay of (5 / 10 ) * 2, and so on. In this example, that just means add a half-second delay for each puff you generate. Also, each time through the loop, it alternates between the smokeL and smokeR animations so that every other puff moves in the opposite direction. One final piece of the total animation style is to set the repeat-count to infinite, so the puffs keep on coming! The function generates new SPAN tags with these animation styles applied and appends them to the parent element, which here is named smoker. It's just a DIV somewhere on the page - all the puffs of smoke will appear to come out of it.

The finished animation. Don't miss it!

I think the effect turned out great. Even though I used a little JavaScript to create the elements, doing all the animation with JavaScript would have been much, much more complicated. I may consider replacing all the old JavaScript-powered animation on Amphibian.com with CSS animation, and fix up my animation editor to go with it!

Now don't miss the smoke effect in today's comic! If you're reading this on the publication day (16 May 2016) the countdown to launch will be live! That means the last frame of the comic will change and do different things right up to the launch time! Keep watching it!

Amphibian.com comic for 16 May 2016

Monday, May 9, 2016

Add Gamepad Support to a Phaser Game

It seems like I haven't written a blog post in forever! It's actually been less than 2 weeks. Right before I took a break, I wrote a little about my new NES-style Bluetooth gamepad. I've been trying off-and-on ever since then to get my 8-bit style platformer to work with it, and today I finally had some success!

First of all, it needs to be said that support for gamepads in the browser is very inconsistent. The W3C's Gamepad API document is still a working draft after all these years (I first read about it and tried it out in 2013). It seems as though Mozilla and Google have some different opinions on how it should work, because the way you interact with the devices varies significantly between Firefox and Chrome. Phaser provides gamepad support through the Gamepad object, but the documentation carries a warning about the volatility of the specification.

Here's what I learned when I tried to use it...

I started with some of the examples on Phaser's site. They worked, most of the time. Let me explain. In theory, working with a gamepad in Phaser is simple. You get a gamepad object, setup a callback to handle the detection of a gamepad device, and bind to buttons in that callback. Then you start the gamepad polling.

function create() {

    // ... setup stuff ...

    var jumpButton = null;

    controller = game.input.gamepad.pad1;

    controller.addCallbacks(this, {
        onConnect: function() {
            // you could use a different button here if you want...
            jumpButton = controller.getButton(Phaser.Gamepad.BUTTON_1);
        }
    });

    game.input.gamepad.start();

    // ... other stuff ...

}

function update() {

    // ... other stuff ...

    if (jumpButton.isDown) {
        // jump code goes here!
    }

    // ... other stuff ...

}

Much like you do for keyboard input, you can set up the buttons you want to listen for in create and then perform actions based on their state in update. And this works pretty well - in Firefox. Chrome, on the other hand, has some issues. Phaser's example code, much like my example above, works most of the time in Chrome when the code gets executed very quickly after the page loads. But if you put enough setup code in front of your gamepad initialization you'll be wondering, like I was, why your gamepad never connects.

I had to dig into the Phaser code in order to figure this out. It works consistently in Firefox because Firefox waits until the first time a button is pressed on a gamepad before it emits a gamepadconnected event from the window object. Phaser catches that and sets everything up, calling the onConnect function when complete. In Chrome, however, gamepads just show up magically at some point after the page is loaded, in an array-like object accessed by calling navigator.getGamepads(). Phaser checks this list constantly, and when things appear for the first time, it makes all the internal setup calls. And right there's the problem! If the gamepads appear BEFORE my onConnect callback function is set up, I missed the boat. A default, no-op callback got executed instead and my gamepad buttons never get set up!

There was no work-around for this that I felt was acceptable, so I actually forked Phaser and fixed the problem in the Gamepad object's code. It was a fairly simple fix - I just don't start polling for those gamepad objects until after the call has been made to game.input.gamepad.start().

I forked off of version 2.4.7 and submitted a pull request, so hopefully my fix makes it in to the next Phaser release and the rest of you won't have to deal with this problem like I had to! If you can't wait, try using my fork and gamepad branch.
UPDATE: My pull request was merged, but not in time for 2.4.8. Look for this fix in the 2.4.9 release!
If you're just interesting in playing the game I've been working on, you can do that here: http://amphibian.com/eight-bit. The full source code is available on GitHub. If you're just interested in viewing today's comic, you can do that here:

Amphibian.com comic for 9 May 2016

Wednesday, April 27, 2016

The Most Awesome Thing on the Internet

Here it is, people. The most awesome thing on the Internet (besides my frog comics) - a
Mariachi Cover of the Dark World theme from The Legend of Zelda: A Link to the Past.




You can thank me later (by viewing and sharing today's comic!). Oh look, here it is...

Amphibian.com comic for 27 April 2016

Monday, April 25, 2016

Review of Xgaming's NES-style Wireless Gamepad

Late last week I received my new Bluetooth wireless gamepad from Xgaming. I was really excited about this new product. I've had one of their arcade joysticks for years and found it to be an excellent piece of hardware that fully lives up to the high expectations set for it on their web site. I was certain that this new wireless gamepad, a bit of a departure from their existing product line, would not disappoint me.


So, what do I think now that I've had a few days to play with it?

Let's start with my initial impressions. It was a little smaller than I had expected it to be. It doesn't really give dimensions anywhere on Xgaming's site (as far as I could tell) but the unit is only 5.125 inches wide and 2.5 inches tall. It's slightly over half an inch thick (not counting the sticks and buttons). For me, the small size makes hitting both sets of top trigger buttons awkward but maybe I just need to get used to it. Most games I play only need one set of top triggers anyway. Besides that, the position of all the buttons and sticks is excellent. It weighs only 3 ounces, but feels very solid. The buttons and D-pad are very firm and have a wonderful feel to them.

Technically, it has been functioning very well. I had no problems pairing it to my Windows 10 PC as a Bluetooth game controller, but it did seem to lose its pairing once (there are colored LED lights on the bottom which indicate things like that - flashing blue means ready to pair). I'm not sure if it was the device's fault or mine - I may have been holding down one of the settings buttons inadvertently while powering it on. I'll withhold judgement on that issue until I see if it repeats. There were no issues setting up button mappings in my emulator software either. It all worked very well.

Playing games with it has been very enjoyable so far. The button response is much better than my old SNES-style USB game controller. I honestly haven't liked a PC game controller this much since my Gavis PC GamePad.

The device is currently selling for about $45. If you love playing emulated NES and SNES games as much as I do, I believe you'll find it to be well-worth the money.

The only question left might be, does it work in web-based HTML5 games such as the 8-bit style platformer I've been working on? The answer is...maybe. Web browser gamepad support is still weird. Phaser has an API for it, but so far I've found it difficult to work with. I'll keep trying and maybe have something to report next week.

Until then, I've got more comics for you to enjoy!

Amphibian.com comic for 25 April 2015