Friday, 23 December 2016

Web Tutorial: Scroll-down Christmas Carol

Christmas Day is looming!

For that, I traditionally write a web tutorial to commemorate the occasion. This year, it will be sinfully simple - a scroll-down card. Y'know, one of those things where content changes on the screen when you scroll.

In order to do that, however, we'll need to start off with a standard HTML layout.
<!DOCTYPE html>
<html>
    <head>
        <title>Xmas Carol</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>

    </body>
</html>


Because we'll be screwing around with div layouts, let's add this to the CSS. It turns all divs a translucent green.
        <style>
            div{background-color:rgba(0,255,0,0.2);}
        </style>


Add a div to the body. The id will be container.
    <body>
        <div id="container">

        </div>
    </body>


This is the style for container. Yep, you didn't read it wrong. The width is set to 100%, and the height is 10 times the height of the screen. Which puts it at a whopping 1000%. This forces the page to be scrollable. However, if you run the code now, you might not see a damn thing even though ideally, you're supposed to see a translucent green overlay.
        <style>
            div{background-color:rgba(0,255,0,0.2);}

            #container
            {
                width:100%;
                height:1000%;
            }
        </style>


You may not see anything until you do this. This ensures that the html and body elements are set at 100% of screen height. This is supposed to be the default, but you know how it is with different browsers...
        <style>
            div{background-color:rgba(0,255,0,0.2);}

            html, body
            {
                height:100%;
                padding:0px;
            }

            #container
            {
                width:100%;
                height:1000%;
            }
        </style>


Now here you go. This is what you should see. padding:0px ensures that there are no ugly spaces at the top.

OK, now let's add another div, id view_wrapper.
    <body>
        <div id="container">
            <div id="view_wrapper">

            </div>
        </div>
    </body>


We style it like so. Width is set to full, height is at 80%, and there's a 5% margin at the top. Most importantly, the position property has been set to fixed so it will remain in the middle of your screen no matter where you scroll.
        <style>
            div{background-color:rgba(0,255,0,0.2);}

            html, body
            {
                height:100%;
                padding:0px;
            }

            #container
            {
                width:100%;
                height:1000%;
            }

            #view_wrapper
            {
                width:100%;
                height:80%;
                position:fixed;
                margin-top:5%;
            }
        </style>


Try it!

One more div nested. Set the id to view.
    <body>
        <div id="container">
            <div id="view_wrapper">
                <div id="view">

                </div>
            </div>
        </div>
    </body>


Style it like this. It occupies 80% of view_wrapper's width, all of its height, and the margin property is set to center it. Properties such as text-align, font-size, font-family and font-weight are optional. Do what you want with those - unless you get really extreme, it won't change the functionality much.
        <style>
            div{background-color:rgba(0,255,0,0.2);}

            html, body
            {
                height:100%;
                padding:0px;
            }

            #container
            {
                width:100%;
                height:1000%;
            }

            #view_wrapper
            {
                width:100%;
                height:80%;
                position:fixed;
                margin-top:5%;
            }

            #view
            {
                width:80%;
                height:100%;
                margin: 0 auto 0 auto;
                text-align:center;
                font-size:5em;
                font-family:verdana;
                font-weight:bold;
            }
        </style>


That's what it should look like now. The view div is meant to contain the content of your text!

Now we're going to write some JavaScript to populate the view div. We start off by declaring a variable lyrics, and populate it with lines from a standard Christmas song. Note that each line is denoted with a "|" symbol.
        <script>
            var lyrics="We wish you a Merry Christmas|We wish you a Merry Christmas|We wish you a Merry Christmas|And a Happy New Year!";
        </script>


Next, we create an array named lines, and set it to contain each line of the lyrics, using the "|" symbol.
        <script>
            var lyrics="We wish you a Merry Christmas|We wish you a Merry Christmas|We wish you a Merry Christmas|And a Happy New Year!";

            var lines=lyrics.split("|");
        </script>


Next, we write a function getScrollPercentage(). It will return the percentage of how much you've scrolled from the top. window.innerHeight has to be multiplied by 10 in this case because you're measuring it against the entire scrollable content, which is 10 times your screen height. The height of container was set at 1000% percent, remember?

So when you reach the bottom, it should be 100%, right? Wrong! And I'll prove it.
        <script>
            var lyrics="We wish you a Merry Christmas|We wish you a Merry Christmas|We wish you a Merry Christmas|And a Happy New Year!";

            var lines=lyrics.split("|");

            function getScrollPercentage()
            {
                return (document.documentElement.scrollTop/(window.innerHeight*10))*100;
            }
        </script>


Add this to your code, and run it.
    <body onscroll="console.log(getScrollPercentage())">


Check your console (Ctrl+Shift+i should do it) and you'll see when you scroll all the way to the bottom, the readout is 90% at most.

So add this line. This is to help decide what percentage of scrollable content to be dedicated to each line, ie. each item in the lines array. Instead of 100%, we only have 90% to work with, so it's (90/lines.length). Since we want to err on the side of caution, we'll round it down using Math.floor().
            var lines=lyrics.split("|");

            var segment_per_line=Math.floor(90/lines.length);

            function getScrollPercentage()
            {
                return (document.documentElement.scrollTop/(window.innerHeight*10))*100;
            }


Now we write the function scrolling(). We set a variable, scrolled, to the current scrolled percentage defined in getScrollPercentage(). Then we get the line number, another variable called line_no, by dividing scrolled with segment_per_line. Erring on the side of caution, again, we use Math.floor() to round it down. Then we set the innerHTML property of the view div to the appropriate item of the lines array.
            function getScrollPercentage()
            {
                return (document.documentElement.scrollTop/(window.innerHeight*10))*100;
            }

            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);

                document.getElementById("view").innerHTML=lines[line_no];
            }


Change this line, and run your code.
    <body onscroll="scrolling()">


So you should get different lines at different scroll heights! Try scrolling all the way down from the top.

The problem with this...

...is that it's not terribly friendly. You scroll, an entire line appears, then as you scroll, it's replaced by a whole new line just like that. In the case of our chosen stanza, the first three lines are identical! How you you even tell when one line changes to the next?!

The answer: Make each word appear individually, by line.

For that to happen, add this to your code. It runs through each item in the lines array and turns it into an array too. So instead of an array of lines, you have an array of arrays, and each of these sub arrays will contain the words to the lines, in sequence!
            var lines=lyrics.split("|");

            var segment_per_line=Math.floor(90/lines.length);

            for (var i=0;i<lines.length;i++)
            {
                lines[i]=lines[i].split(" ");
            }

            function getScrollPercentage()
            {
                return (document.documentElement.scrollTop/(window.innerHeight*10))*100;
            }


In other words, instead of this...
lines[0] "We wish you a Merry Christmas"
lines[1] "We wish you a Merry Christmas"
lines[2] "We wish you a Merry Christmas"
lines[3] "And a Happy New Year!"

...you get this!
lines[0] ["We","wish","you","a","Merry","Christmas"]
lines[1] ["We","wish","you","a","Merry","Christmas"]
lines[2] ["We","wish","you","a","Merry","Christmas"]
lines[3] ["And","a","Happy","New","Year!"]

Now modify your scrolling() function. The variable segment_completion gives you how many total segments has been completed already. So, for example, if you're at line number 3 and each line is 5% of scroll completion, you have scrolled at least 15%! The next line would be at 20%, so how many words of the current line you display will be the progress you've made from 15% to 20%.
            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);
                var segment_completion=line_no*segment_per_line;

                document.getElementById("view").innerHTML=lines[line_no];
            }


For that, we'll create a few function, getWordsFromLine(). We'll use this function to determine how many words from the current line (which is now an array, remember?) to display, and display those words instead of the entire line. For that, we pass in the entire sub-array from the lines array which will be defined as lines[line_no], and a value which gives you the percentage scrolled since the last completed segment.
            function getWordsFromLine(line,completion)
            {

            }

            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);
                var segment_completion=line_no*segment_per_line;

                var words=getWordsFromLine(lines[line_no], scrolled-segment_completion));
                document.getElementById("view").innerHTML=words;
            }


Here, we calculate the completion percentage of the current segment, and assign it to the completion_ratio variable. Then we use this ratio to determine how many words out of the entire line will be displayed, using the number of words (line.length) and completion_ratio.
            function getWordsFromLine(line,completion)
            {
                var completion_ratio=(completion/segment_per_line);
                var words_displayed=Math.ceil(line.length*completion_ratio);
                var words="";
            }


After that, we iterate through the line array using a For loop, adding the necessary number of words, and return the string generated.
            function getWordsFromLine(line,completion)
            {
                var completion_ratio=(completion/segment_per_line);
                var words_displayed=Math.ceil(line.length*completion_ratio);
                var words="";

                for (var i=0;i<words_displayed;i++)
                {
                    words+=line[i]+" ";
                }

                return words;
            }


Run your code! What happens? Bet it worked, didn't it? But you may run into a small problem near the end because lines[line_no] may be undefined due to line_no being larger than the total number of items in lines. So just do this...
            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);
                var segment_completion=line_no*segment_per_line;

                var words=(lines[line_no]==undefined?"":getWordsFromLine(lines[line_no],scrolled-segment_completion));
                document.getElementById("view").innerHTML=words;
            }


What it basically does is check if lines[line_no] is undefined, and returns an empty string if so. If not, run the getWordsFromLine() function as per normal.

Further improvements?

Well, now your lines appear word by word, but they skip onwards to the next line without pause. That's really unnatural.

So just modify your code like so. Instead of a single "|" symbol, we use a double "||". This ensures that the lines array has more items, specifically an empty item between each line of the song.
            var lyrics="We wish you a Merry Christmas||We wish you a Merry Christmas||We wish you a Merry Christmas||And a Happy New Year!||Good tidings to you||To you and your kin||Good tidings for Christmas||And a Happy New Year!";


Run your code. Is there a nice pause between each line? But let's add an If conditional to this. As in, the content only changes if there are actually words to display. Re-run your code. Now there won't be any blank pauses between each line!
            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);
                var segment_completion=line_no*segment_per_line;

                var words=(lines[line_no]==undefined?"":getWordsFromLine(lines[line_no],scrolled-segment_completion));

                if (words.length>0)
                {
                    document.getElementById("view").innerHTML=words;
                }
            }


So now you have a nice scrolling card. Let's change the background a bit to remove the placeholder green.
            div{background-color:rgba(0,255,0,0.0);}


Then we'll add this tile to spruce things up.

xmas2016_bg.jpg

            body
            {
                background:url(xmas2016_bg.jpg);
            }


Nice, right?!


Little extras - a mini caroller

Now, for all intents and purposes, your scrolling card is done. But here's a little something to complement the look. I've added the HTML and CSS for a little South Park type caroller. I'm not going to show you how it's done because that's totally not the point of this tutorial at all, but here's the code anyway.
            <div id="view_wrapper">
                <div id="view">

                </div>
                <div id="caroller">
                    <div class="head" id="head">
                        <div class="hair">

                        </div>
                        <div class="mouth" id="mouth">

                        </div>
                    </div>
                    <div class="body">
                        <div class="sheet">

                        </div>
                    </div>
                    <div class="feet">

                    </div>
                </div>
            </div>


Here's the CSS. Change the colors if you like.
            #view
            {
                width:80%;
                height:100%;
                margin: 0 auto 0 auto;
                text-align:center;
                font-size:5em;
                font-family:verdana;
                font-weight:bold;
            }

            #caroller
            {
                width:200px;
                height:300px;
                margin: -20% auto 0 auto;
            }

            #caroller .head
            {
                width:100px;
                height:100px;
                background-color:#AA4400;
                border-radius:50%;
                margin: 0 auto 0 auto;
            }

            #caroller .head .hair
            {
                width:100%;
                height:50%;
            }

            #caroller .head .hair::before,#caroller .head .hair::after
            {
                content:"";
                display:block;
                width:60%;
                height:100%;
                background-color:#000000;
            }

            #caroller .head .hair::before
            {
                border-radius:70% 0%;
                float:left;
                margin-left:-10%;
            }

            #caroller .head .hair::after
            {
                border-radius:0% 70%;
                float:right;
                margin-right:-10%;
            }

            #caroller .head .mouth
            {
                width:0px;
                height:0px;
                background-color:#000000;
                border-radius:50%;
                margin: 10% auto 0 auto;
            }

            #caroller .body
            {
                width:180px;
                height:150px;
                background-color:#AA0000;
                border-radius:40% 40% 0% 0%;
                margin: -5px auto 0 auto;
                padding-top:10px;
            }

            #caroller .body::before,#caroller .body::after
            {
                content:"";
                display:block;
                width:50px;
                height:50px;
                border-radius:50%;
                background-color:#FFFFFF;   
            }

            #caroller .body::before
            {
                float:left;
                margin-left:-10%;
                margin-top:50px;
            }

            #caroller .body::after
            {
                float:right;
                margin-right:-10%;
                margin-top:-30px;
            }

            #caroller .sheet
            {
                width:80%;
                height:50%;
                background-color:#FFFF00;
                margin: 0 auto 0 auto;
            }

            #caroller .feet
            {
                width:150px;
                height:50px;
                background-color:#440000;
                margin: 0 auto 0 auto;
            }

            #caroller .feet::before,#caroller .feet::after
            {
                content:"";
                display:block;
                width:60%;
                height:80%;
                border-radius:50% 50% 0% 0%;
                background-color:#220000;
                margin-top:10px;
            }

            #caroller .feet::before
            {
                float:left;
                margin-left:-10%;
            }

            #caroller .feet::after
            {
                float:right;
                margin-right:-10%;
            }


Cute little bugger, isn't he?!


Now do this to your JavaScript. This ensures that the head and mouth move in random directions when there are words to "sing", and stays still otherwise.
            function generaterandomno(varmin,varmax)
            {
                return Math.floor((Math.random() * (varmax-varmin+1)) + varmin);
            }

            function scrolling()
            {
                var scrolled=getScrollPercentage();
                var line_no=Math.floor(scrolled/segment_per_line);
                var segment_completion=line_no*segment_per_line;

                var words=(lines[line_no]==undefined?"":getWordsFromLine(lines[line_no],scrolled-segment_completion));

                if (words.length>0)
                {
                    document.getElementById("view").innerHTML=words;
                    document.getElementById("mouth").style.height=generaterandomno(10,30)+"px";
                    document.getElementById("mouth").style.width=generaterandomno(10,50)+"px";
                    document.getElementById("head").style.transform="rotate("+generaterandomno(-5,5)+"deg)";
                    document.getElementById("head").style.webkitTransform="rotate("+generaterandomno(-5,5)+"deg)";
                }
                else
                {
                    document.getElementById("mouth").style.height="0px";
                    document.getElementById("mouth").style.width="0px";   
                }
            }


Merry Christmas!

You can vary things by changing the lyrics. It should still work unless you substitute the lyrics with something long and rambling (like one of Roy Ngerng's speeches) going over 100 lines or so.

That's how I (sc)roll, baby.
T___T

Sunday, 18 December 2016

Five User Interface Wins

Last year, I wrote a listicle about five user interface fails. In the interest of balance, I'm going to bring you five user interface wins.

Groovy!

These are five little things that while not groundbreaking, do make life easier for the user above and beyond the call of duty. Things not just done right, but done excellently. This, incidentally, is in accordance to the second Great Virtue of a Developer - Impatience.

1. The Nationalistic List

You know those pesky drop-down lists of countries you have to use whenever you fill out a form that asks for your address? This drop-down does one better. It anticipates what country you are hailing from (based on guesswork, IP address or somesuch) and puts that country at the top of the list. How excellent is that?! Sure, it's a small touch... but in user experience, the small things do matter.
Country:


2. Preemptive Login screen

You're probably familiar with the standard login screen where you have to fill in your id and password. This can be a major pain in the ass if you're confronted with a "invalid login/password" message after typing in both fields.

This login screen does it better. First, you enter an id, and if the id doesn't match any id in the database, you simply don't proceed. Go on, try it. Enter any value. The "Next" button doesn't become clickable until you enter "teochewthunder". And then it asks you for the password. This saves you a bit of typing if you enter an incorrect id.

3. Overlaid Operation

Want to save screen space? Don't want to dedicate an entire page to what amounts to a simple operation? Use an overlay for, in this example, registration. The main advantage is that you don't get taken away from whatever you were doing. You're still on the same page. The other advantage is that in an age where screens are getting smaller, this saves you some valuable real estate.
x close

Registration

Name
Email
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.



4. Explanatory Rollover Buttons 

The button is obviously clickable and self-explanatory, but when you mouse over, there's more information. Sure, this probably won't work on a touch-screen information, but on a conventional interface, it adds value. The win here is that absence of the additional value will not take away from the usefulness of the original button. It's just the icing on top of an already very edible cake.

50% off
selected products!
BUY NOW

5. Searchable Lists 

Frameworks such as jQuery Mobile already have APIs for this cool little feature. Say you have a long-ass list of stuff and don't want to scroll through all of it. I don't blame you - who would? You type in whatever you're searching for, and the list gets truncated down to your search results! Pretty neat, eh?

The example below reuses the list of countries in the first example.


So much win.

There's so much more I could add to this list, but the sheer awesomeness might just cause your skull to implode. As technology improves, UI and UX have become increasingly sophisticated. These aren't even the most impressive things you'll find out there.

Sadly, simply because stuff like this is so commonplace, the ingenuity of these little things often goes unlauded. Well, no longer.


Cool button signoff!
T___T

Wednesday, 14 December 2016

The Fisherman's Bend Analogy

I love analogies. Besides making me sound all knowledgeable and shit, they help explain web development concepts that people may have trouble understanding otherwise.

It's time for another analogy. In particular, a ropework analogy, in the vein of the Bowline Bend Analogy which I posted last year. As I may have mentioned previously, I spent a couple years out at sea in service to the Republic of Singapore Navy. So yes, I do know my way around a bale of rope.

The Fisherman's Bend 

Also known as the Anchor Bend, it is a common sailor's knot used to hitch a load to a post. Below is an illustration on how to tie it...

Make one round turn around a post.

Bring the end under the round turn, in a half-hitch.

Secure that with a second half-hitch. There's your Fisherman's Bend!

Round Turn and Two half-hitches 

The Fisherman's Bend is similar to another common sailor's knot, the Round Turn and Two Half-hitches.

Make one round turn around a post.

Secure that with a half-hitch.

End with a second half-hitch.

The Differences 

The Fisherman's Bend has the added security of having the first half-hitch interweaved with the initial round turn. It's also commonly accepted that of the two knots, the Fisherman's Bend is considerably more secure. Does it follow, then, that the Round Turn and Two half-hitches is obsolete and should be deprecated?

Not so.

Ideally, one should always use the more secure knot whenever possible. But situations are rarely ideal. The Fisherman's Bend is applicable when the load to be secured has not yet been applied; ie. the rope is not under strain while the knot is being tied. If the other end of the rope is hitched to a moving vessel, for example, attempting to tie the Fisherman's Bend may result in you losing your fingers. In such situations, one opts for the less secure but eminently more feasible Round Turn and Two Half-hitches.

What does this have to do with web development? 

Not just web development, but software development in general. There are some practices, such as the Goto statement, which are considered anathema to "proper" structured programming. A solid long-term solution is generally considered better than a quick dirty fix. But, as the Fisherman's Bend has shown us, best practices are situation-dependent. If a "proper" solution, in order to be implemented, would result in a downtime of about half an hour on a system that typically transacts millions of dollars per minute, what would management prefer - a proper solution or the quick dirty fix? You bet your sweet ass most of the time they'll opt for the latter.

A proper solution may result in better, more maintainable, more extensible, more everything software. But the value of that software is intangible, whereas the loss of several minutes of transaction time will be felt now. A software developer may feel differently of course - we're supposed to feel differently. Unfortunately, we don't make the rules. In these cases, immediate pragmatism wins out. There is little point in having a system that will reap benefits (in terms of cost savings) five years down the road, when a quick and dirty fix will take care of the problem now, with noticeably less downtime, and perhaps cause maintainability issues five years down the road.

Incidentally, this is also why people make loans which they have to pay interest on. Because waiting ten years to save the same amount of money makes absolutely zero sense when you consider inflation, and the fact that you need the money now, not ten years later.
The (b)end,
T___T

Tuesday, 6 December 2016

Spot The Bug: A Nasty Angular String Surprise

Spot the Bug is back!

Didya miss me?!

Today, we'll be examining something I ran into while experimenting with AngularJS.

AngularJS seemed like a fun thing and useful thing to pick up. I wasn't disappointed on that score. But man, was it ever frustrating in places!

So I had managed to create a drop-down list in AngularJS, and populate it with months of the year. I then set the default value to "May". Upon reloading the page, instead of the value "May", it was displaying a blank. What gives?


What I saw upon reloading the page...

This is the front-end code.
<!DOCTYPE html>
<html>
    <head>
        <title>Angular Test</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script src="js/main.js"></script>
    </head>

    <body ng-app="monthApp">
        <div ng-controller="monthCtrl">
            <form id="frmMonth" name="frmMonth" novalidate>
                <label for="ddlMonth" class="control-label">Month </label>
                <select id="ddlMonthFrom" name="ddlMonthFrom" class="form-control" ng-model="monthfrom" required>
                    <option value="">(select one)</option>
                    <option ng-repeat="month in list_months" value="{{month.id}}">{{month.name}}</option>
                </select>
                <button class="btn btn-default pull-right" ng-disabled="frmSchool.$invalid" ng-click="update()">Update</button>
            </form>
        </div>
    </body>
</html>

This is the controller in main.js.
var app = angular.module("monthApp", [])
.run(function($rootScope,$http)
{
    //month list
    $rootScope.list_months=[];
    for (var i=0;i<12;i++)
    {
        $rootScope.list_months.push({id:(i+1),name:getmonthname(i+1)});
    }
});

app.controller("monthCtrl", function($scope,$rootScope,$http)
{
    $scope.list_months=$rootScope.list_months;
    $scope.month=5;
});

function getmonthname(varmonth)
{
    if (varmonth==1) return "Jan";
    if (varmonth==2) return "Feb";
    if (varmonth==3) return "Mar";
    if (varmonth==4) return "Apr";
    if (varmonth==5) return "May";
    if (varmonth==6) return "Jun";
    if (varmonth==7) return "Jul";
    if (varmonth==8) return "Aug";
    if (varmonth==9) return "Sep";
    if (varmonth==10) return "Oct";
    if (varmonth==11) return "Nov";
    if (varmonth==12) return "Dec";
}

When I used my browser to inspect the element, I discovered some code inserted into the drop-down list. Which caused the drop-down list to have a new item and the default value set to that item. Weird, huh.

                    <option value="? number:5 ?"></option>
                    <option value="">(select one)</option>

What went wrong

Apparently, AngularJS code for list item comparisons only recognizes strings. My values were integers. And if none of the items in the list matched the conditional, it would insert one new item in there, with an empty string, just so that conditional would return true.

How I fixed it

Added this quick cheap fix to the code. Instant string conversion! It worked!
app.controller("monthCtrl", function($scope,$rootScope,$http)
{
    $scope.list_months=$rootScope.list_months;
    $scope.month="5";


 

Moral of the story

I'm just gonna say I don't really feel that this one is my fault. This is JavaScript. JavaScript is supposed to be dynamically typed. What AngularJS does, doesn't feel at all consistent with JavaScript in this sense. Seriously, whatever happened to coercion?

Looks like the bug's been caught. High five,
T___T

Friday, 2 December 2016

App Review: Alien Creeps

Like the Tower Defense genre? You could do worse with Alien Creeps, a game by Outplay Entertainment.

The Premise

Earth is under attack by monstrous aliens and it's your job to keep them at bay. Yes, I know, hardly original. In fact, it's a concept that's been flogged to death over and over. Still, this is a Tower Defense game. It should, and will be judged by other factors. As such, any half-decent plot will do.

The Aesthetics

Visually, Alien Creeps does pretty well. Graphics are suitably cartoony, in fitting with the comic feel of the game. Animations are cute.




The Experience

As with most other Tower Defense games, upgrades are made available when you collect enough in-game currency to purchase them. The upgrades are pretty inventive and provide plenty of nifty visual effects in addition to killing aliens in very interesting ways.

The mood is set for maximum campiness; if the visuals don't immediately clue you in, the dialogue will.

The Interface

For the most part, the controls are fine and dandy. Easy enough to use without screwing up. One complaint I do have is with the Tesla, because using it involves clicking and swiping. This can cause the screen to move, which can be a royal pain in the butt when you're in real-time mode and aliens are pouring in thick and fast.

What I liked

Alien Creeps ramped up on the funny. The Head Villain was a delightfully snarky alien. The Commander and Engineer, your character's allies, also indulge in a fair bit of wisecracking.










Upgrades and optional buys. You can buy Allies to help in your defense. They come in a variety of shapes, sizes and abilities. Creatively, they're a hoot.



Replay value was limited, but the game was not as repetitive as some others I've played. There is a variety of ways in which to kill stuff and pass stages, so things don't get stale all that fast.

What I didn't

In some of the stages, difficulty level seemed just a little too off-putting. There were stage levels which I suspect would be impossible to pull off without spending money.... or even with spending money.

Most of the aliens just seemed a bit by-the-numbers to me. Sure, they came in many different sizes, colors and degrees of toughness, but other than a few standouts, they were all just fodder.

Having flying aliens follow the same predefined paths as walking units, just seems rather implausible.

Game ended just a wee bit too soon after 20 plus stages. Could have done with more stages.

Conclusion

Despite its limited size, Alien Creeps is a decent offering for its scope and genre. It should keep you busy for a couple weeks or so.

My Rating

7 / 10

Try Alien Creeps today. It's out of this world.
T___T