Friday, January 29, 2016

A Slider Control for the Web

Today's comic has a slider control embedded in the third frame, allowing you to adjust the brightness of the sun and extend daylight. It's suppose to look a bit like the brightness slider control on your phone. I got the idea from my daughter who keeps her brightness on the lowest setting in order to extend the battery life. She also panics when it gets down to 70%, as if a dead phone battery will somehow mean her own death as well. Teenagers...

You might assume that a big fan of HTML5 such as myself would use the range input field to implement the slider. You would be wrong. Unfortunately, I do try to keep the comic mostly compatible with IE9 (that might change be the end of the year) and it does not support the range type of input. Also, the default styling of the range slider looks pretty terrible. It would have taken me a while to get something that looked the way I wanted.

A standard HTML5 slider control. Input type "range" does this.

Well, how about the jQuery Mobile slider? It looks nice, and I already use jQuery. But, alas, its mobile styling really messed up the default styling of all kinds of things on my pages. It would have taken me quite some time to straighten it all out.

The jQuery Mobile Slider control. Looks nice, destroys Amphibian.com.

So twice I was thwarted by wanting a slider that looked nice and didn't cause me to do a lot of extra work. Before I gave up on this idea, I found the Slider for Bootstrap by Kyle J. Kemp. It came with CSS that didn't interfere with the rest of my CSS, and was easy to use.

Start by including the bootstrap-slider.js (or bootstrap-slider.min.js) file on your page. Also include the bootstrap-slider.css (or bootstrap-slider.min.css). Then write some HTML like this:

<input id="brightnessSlider" type="text"
       data-slider-tooltip="hide"
       data-slider-id="bSlider"
       data-slider-min="0"
       data-slider-max="19"
       data-slider-step="1"
       data-slider-value="19"/>

Note that the type of the input is "text" and not "range." Don't worry about that for now, look at the data-slider- attributes. These are used to pass configuration settings to the control. In my case, I wanted to hide the tooltip, set the minimum value to 0, the maximum value to 19 (for 20 total values), the stepping to 1, and start with a value of 19 (the max). The data-slider-id attribute is of interest, though. What it means is that when the JavaScript turns this input into a bunch of other elements that look like a slider, the parent div for all those will be named "bSlider". Once that's created, this text input will be hidden from view. But when the user interacts with the slider, the value will be written back to the text input's value - making it easy to figure out what to use when the form is submitted.

Take a look at the JavaScript now.

var bChange = function() {

    var n = Number($('#brightnessSlider').val());
    console.log("current value is " + n);

};
    
var bslide = $('#brightnessSlider').slider()
                    .on('change', bChange);

In this example, the bChange function doesn't really do much, but it shows how you can get the current value of the slider. The bChange function is passed in as the event handler for the change even when the slider is created.

If you want to change the width of the slider, the only way I found was to alter the CSS width attribute of the control's created div. I did this programmatically when the comic is displayed in one of the small-screen formats. Remember, the control's div will have the id matching the data-slider-id attribute in the input tag.

$("#bSlider").css("width", "150px");

The default width seemed to be 210px, but I reduced that to 150px for the phone screen sizes.

The styled slider in the comic.

After that, I added a few CSS rules to change the colors of parts of the slider, and I ended up with pretty much exactly what I envisioned it should look like. For now, this is the slider control that gets my recommendation - as long as you also use jQuery and Bootstrap. But who doesn't these days?

See the slider in action in today's comic!

Amphibian.com comic for 29 January 2016

Wednesday, January 27, 2016

Less Snow, More Snow Days?

The schools here were closed today. A snow day? No, it didn't snow. This has become normal it seems. The schools here in Pennsylvania close for bad weather much more than they ever did when I was in school.

Today the reason was a forecast of freezing rain. I'm not sure if there was any freezing rain. But they also sometimes close in advance due to a forecast of snow. The next day when the snowfall is much less than predicted (or doesn't materialize at all) it seems ridiculous that the kids had to miss school. Do they call and un-do the closure? No, the kids just stay home.

They also close school when it just gets too cold. I'm fairly certain that I had to stand outside waiting for the school bus in temperatures in the single digits - when measured in kelvin. I have to wonder if they give days off school when it gets too sunny in places like Florida.

The other thing that is missing from schools today is the 1-hour delay. When I was a kid, we had 1-hour delays, 2-hour delays, and complete cancellations. I can remember only a few early dismissals. I don't think 1-hour delay is an option anymore. There's never been one since my kids have been in school. What happened to them? Did snow plows get slower? Is it not possible to clear the roads in an hour anymore?

I don't know how these rampant closures prepare the children for adulthood. I don't get the day off when it snows. They get to stay home, but I have to drive my car in those terribly unsafe conditions to get to my job.

Why don't we just get school buses like this one?



I probably sound old now. When I was a kid we had to walk to school in the snow uphill both ways while being chased by bears! Well that's enough of my ranting about school closures, time to read today's comic. It never snows in the comic. Maybe it should. I don't know what the frogs would do in the snow.

Amphibian.com comic for 27 January 2016

Monday, January 25, 2016

Run Your Own Comic

Mechanical frogs, for repeatable
 installations of Amphibian.com
As you may have heard, the East Coast got hit by a major snow storm this weekend. It started snowing Friday night and snowed most of the day Saturday. Since I couldn't go anywhere I was able to get a lot done - making some new comics and enhancing the platformer game that I've been working on.

But before I did any of that, I finished checking in files and instructions for repeatable installations of the Amphibian.com webcomic application. I started doing this over a year ago, but never finished it. The goal was to have all of the files and complete keystroke-level instructions necessary to set up Amphibian.com on a new Ubuntu instance.

Why do I want this? Currently, the comic is running on an Ubuntu virtual machine hosted by Digital Ocean. Digital Ocean is great and I hope they're around for a long time, but what if they aren't? Or what if another service comes along for a better price? Or what if I just want to set up another instance somewhere for test purposes?

The complete installation includes:


I sat down in the morning with VirtualBox, the Ubuntu 14.04.3 server ISO image, and got to work. I created a fresh virtual machine with a clean install of Ubuntu and documented all the steps I had to perform to get the comic running. When I thought I had all the commands documented, I started from scratch with a new virtual machine and did it all again by just copying and pasting commands. Of course, I missed a few. I updated my document and tried again with a third virtual machine. That time, everything went well and I had Amphibian.com running in under 10 minutes.

The things that I was really missing were database setup scripts (to make the database, user, and tables), the site configuration files for Nginx, and a script to start and stop the application. I added those to the repository along with my complete setup instructions and now I feel a lot better. Not only does it allow me to have the confidence that I can recreate my application if I ever need to, but it allows other people to easily set up and run my application as well. Maybe you'd like to try it, and make your own comic?

Here is the link directly to the INSTALL.txt file in the repo on GitHub, so you can check it out.

What's next? Maybe complete automation of the setup using something like Puppet. That way I could take advantage of an auto-scaling service like AWS offers, so when my comic gets insanely popular I won't have to worry about long response times. It could happen.





As a side note, I found out while I was doing this that a new major version of PhantomJS was recently released. This 2.0.0 has some major differences and actually fixes some bugs that I've encountered while using it to generate the static images of my comics. Unfortunately, there is no binary distribution available for Linux yet - so my installation instructions for Amphibian.com actually include building PhantomJS 2.0.0 from source. That takes a long time, so I'm keeping my binary around in case I need it again before the official ones are available. If you would like it (built for Ubuntu 14.04.3 64-bit) just let me know and I'll give you a link.



If you're done setting up your own copy of Amphibian.com now, click the picture below and view my Amphibian.com comic for today!

Amphibian.com comic for 25 January 2016

Friday, January 22, 2016

Training Days

I've only had one day of "real" work in the last two weeks. I have been attending lots of trainings. Last week it was DoDAF and Cyber security architecture. This week it's Amazon Web Services. Next week it will be more Amazon Web Services. I haven't sat in class this much since college.

Now, I'm not complaining. It's great that my company is investing so much in me and is helping me to become a better software architect. It's just that I have a hard time with formal classroom-type training and so much of it at once is wearing me out.

I'm self-taught in most areas of software. Sure, I have a Bachelor's degree in Computer Science...but that was a formality. I had already learned (the hard way) just about every concept I was taught in my major courses. I suppose I learned something in my general education classes, probably. I'm not entirely sure that I would have been ready for a job as a professional software engineer had I not been writing and selling commercial software before going to college and working on cutting edge stuff on the side while in college. But that's just me.

I guess I have a Master's degree in software engineering as well. But I got that after already working as a software engineer for 12 years. I'm sure I learned something in the course of getting that degree, but it's all mixed up in my mind with things I learned on the job.

I really like to learn by selecting a technology of which I know very little and then building something with it. Academic exercises don't do it for me. I need to make something. I need to make something real and practical. That's how I learn.

It's been a struggle, but I'll survive. Hey, why don't you click on the picture below and look at the comic I made for today? You won't learn anything from it, I promise.

Amphibian.com comic for 22 January 2016

Wednesday, January 20, 2016

A Match-3 Tile Game in Phaser

It's finally here! The day I release the comic containing my match-3 game! I've been working on this thing for way too long. When I had the idea to put one of those classic tile-matching games in a comic (you know, like Bejeweled) I had thought that it would be easy to put together. I used Phaser, course, but I was unprepared for just how much goes in to one of these things.

Getting this one simple game embedded in the 3rd frame of the comic came in at a couple hundred lines of code. Like everything else in my comic, you can see the complete source code on GitHub (this link goes directly to the game's .js file) so I won't bother to post the whole thing here. But one concept came up more than once during the development which I'd like to talk about.

Tile Matching game with Amphbian.com's frogs

The issue was that I needed to do Phaser Tween animations on possibly over 20 sprites at once, and then take some other action when they had all finished. Making a single Tween call a function when complete is rather straightforward, but what is the proper mechanism for firing off an event when a bunch of other asynchronous events have completed?

Here's an example of a Tween that calls a function when complete:

var tween = game.add.tween(sprite.scale);
tween.onComplete.add(someFunction);
tween.to( { x: 1, y: 1 }, 500,
    Phaser.Easing.Linear.None, true, 0, 0, false);

The above code creates a Tween that will change the x and y fields on sprite.scale both to 1 in 500 milliseconds. When complete, the function someFunction will be called.

Now what if I had 5 Tweens that all take different lengths of time to finish, and I don't want to execute a function until they are all done? Sure, I could just call the function when the longest one is complete, but what if they don't even all start at the same time? It could get messy. The solution is to make a little closure function that counts completions and then executes a callback function when the counter reaches a set level. Here is what I mean...

var num = 5;

var counter = function(total, callback) {
    var t = total;
    var c = 0;
    return {
        inc: function() {
            c++;
            if (c === t) {
                callback();
            }
        }
    };
}(num, someFunction);

var tween = game.add.tween(sprite.scale);
tween.onComplete.add(counter.inc);
tween.to( { x: 1, y: 1 }, 500,
    Phaser.Easing.Linear.None, true, 0, 0, false);

// now make 4 more Tweens here, with different lengths


Assuming I know how many Tweens I'm going to make, which is 5 in my example above, I can declare an anonymous function and then immediately call it passing in that number along with the function I want to use as the callback. That anonymous function creates a closure and returns an object (assigned to the variable counter) with a function inc. Every time counter.inc is called, it increments the internal counter and checks to see if it is equal to the expected total. If so, callback is executed - and here callback is someFunction. The onComplete event on the Tweens just has to call counter.inc and everything goes off like expected. Once all five are done, no matter how long it takes, someFunction will be called.

I ended up using this pattern in two different places in my match-3 game. My game certainly isn't the best example of a classic match-3 tile game but it's also meant to be a joke in a comic. If you're interested in how it works anyway, be sure to check out the source code. At the very least, look at the comic and match up some frogs!

Amphibian.com comic for 20 January 2016

Monday, January 18, 2016

A Phaser Game With Mouse/Touch Input

I'm back from Texas and have mostly recovered from the events of last week. I still have a bit of a cold, but I'm not letting it stop me from getting a simple game ready for inclusion in a comic this week. This game will use mouse/touch input instead of the keyboard like my last one did, so I had to figure out how to use sprite dragging in Phaser.


Like most things have been with Phaser so far, it took a few tries to get it all correct but in the end it all seems really simple. It revolves around enabling input on individual Sprites, enabling drag, and then optionally listening for drag-related events.

Here is the complete source code for a Sprite-dragging demo:

var init = function() {

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

    function selectFrog(sprite, pointer) {
        console.log("selected");
        sprite.frame = 1; // frog in the air
    }

    function releaseFrog(sprite, pointer) {
        console.log("released");
        sprite.frame = 0; // frog sitting
    }

    function preload() {
        this.load.spritesheet('frog', 'assets/sprites/frog.png', 79, 60);
    }

    function create() {

        this.stage.backgroundColor = "#999999";

        var frog = this.add.sprite(50, 50, "frog", 0);
        frog.inputEnabled = true;
        frog.input.enableDrag(true);
        frog.events.onDragStart.add(selectFrog, this);
        frog.events.onDragStop.add(releaseFrog, this);

    }

};

window.onload = function() {
    init();
};

The selectFrog and releaseFrog functions are the event handlers for the drag start and drag stop events. In this example, all they do is log something to the console and change the frame of the sprite. In my upcoming game, I do more in here such as tween animations and game logic.

When I make the frog sprite in the create function of my example, setting inputEnabled to true is the first step. Without this, you can't do anything with input to the individual sprite. Once that is done, you can set the specific input behaviors. The very next line, frog.input.enableDrag(true), turns on drag-ability. The single parameter passed to the function sets whether or not the Sprite should re-center itself to the cursor upon being drug. I passed true, which will cause the center of the sprite to jump to the position of the cursor when the drag starts. If this isn't what you want, you can also say false and drag from any part of the sprite - not just center.

When dragging is enabled, the sprite will fire off events for drags starting and stopping. I added the selectFrog and releaseFrog functions as event handlers using the onDragStart and onDragStop fields of the sprite's events field. Note the parameters that get passed to these event handlers when they fire. The first is the sprite object that was the subject of the drag and the second is the Pointer object. There's lots of information on the Pointer object about the state of the pointer if you want any of that to matter in your game.

If you've tried the code above and are using a mouse, you might be disappointed that the cursor changes to that text-select I-beam cursor thing while you drag the frog. If you'd like it to stay as the default cursor while you drag, no problem! You can simply override the cursor style in the create function. Just add this line:

this.game.canvas.style.cursor = "default";

Now the cursor will always be the default pointer regardless of what you are clicking or dragging in the game. If you'd like the cursor to turn into the click-here hand whenever it's over the frog (dragging or not), there's also the useHandCursor field on the input object. If you add this line to the create function instead...

frog.input.useHandCursor = true;

...it will turn the cursor into the hand when you mouse-over the frog. I didn't care for that personally, but it might be useful in certain situations.

Now that you've read all this, you probably want to see this sprite-dragging in action. Sorry, but the game I was making is not actually in today's comic. You have to wait until later in the week. Click the image or link below for today's comic.

Amphibian.com comic for 18 January 2016

Friday, January 15, 2016

Least Productive Day Ever

This hasn't happened in a very long time, but I have absolutely nothing of interest to share today. I've been in training all day, ate some dinner, and then couldn't get anything to work with the comic game for next week. I think I'm too tired. I have one more day here in Dallas, so I found a nearby movie theater and went to see Star Wars again. I took the stuffed frog with me.


Hopefully I'll have something better next week, including better comics. For now, you get this one.

Amphibian.com comic for 15 January 2016