Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Android vs. CraigDJ

4.91/5 (24 votes)
13 Jan 2014CPOL11 min read 58.3K   1.2K  
I've created an Android Game with the aid of HTML5, CSS, Javascript, Node.js, and PhoneGap, and this is how I did it.

Image 1

Introduction 

Hello and welcome to my Android app project! 

I need to confess that I still know pretty much nothing about the native Android environment - here is my reckless dive into the Android section of CP. Instead of learning a completely new environment and langauge, I've built my game using HTML5, CSS, and Javascript, and ported it to Android using an open-source project called PhoneGap. I've been updating this article as my project has progressed - but still stay tuned and don't forget to vote and comment!

What was my app idea? 

Today our LCD displays can display millions of colors, and our eyes are supposed to be able to detect millions of colors. I imagined a simple game that tests the human eye to the extreme.

There were several ways to do this, but foremost in my mind was a vision of computer generated dots sliding down a screen. Imagine that all the nearly all the dots are the same color except for a few that the app modifies slightly by adding or taking a little of R, G, or B. The user's goal would be to tap the off-colored dots (and maybe shoot them to the side of the screen).

Several game modes could be created - timelimit, online (against other players), play-as-long-as-you-like-to-earn-points-and-gizmos, and multi-color (for extra difficulty)

The user could customize the base color. The dots could even be synchronized to music.

The app could keep track of what sort of color modifications the user is best at spotting and display this information in the user's profile for the user's interest. Several in-game collectables (things floating down with the dots) could be color-enhancers (to make spotting differences easier), points, bombs(don't collect these!), and temporary slow-downs.

Setting Up 

I am a self-confessed Android newbie. Assuming that you are the same, this is what you will need to get started. 

  • You will need a Java Development Kit (JDK). Download and install this from here.
    This kit also includes a full JRE, if you don't already have one.
  • Download and install the Android SDK. The SDK doesn't come in an installer, so I reccommend that you create a new folder to place the sdk files in (perhaps in Program Files, or beside your document/pictures/videos).
  • And, if you don't have it already, I recommnd installing GIMP, a free and very powerful image editor. I used it to create a few of the graphics in this game.

Checking out the Native SDK

You are now supposed to have everything you need to develop for Android. Now take a moment with me to poke the SDK. See what it feels like.

  • Open Eclipse (double-click /eclipse/eclipse.exe).
  • Navigate to File>>New>>Android Application Project and click.

    Image 2
  • Follow through without changing anything to the finish.
  • You can attach your android device (if you have one) and run your first app on it. I don't have an Android, so I didn't do this step.

Now I got to this stage with my app before I stopped. Learning a whole new environment and language suddenly seemed too painful. I had the equipment, but I had no idea how to use it. 

HTML5? Node.js? What the ...?

I really didn't feel like learning native Android development simply to write this app. I was aware that apps could be built using web technologies, and I decided to explore this path. I've still learnt a lot, it was just less painful!

Here's a side by side comparison:

Native Environment

  • Extremely powerful
  • Suburb performance
  • Completely unfamiliar (IDE, Language, everything)

PhoneGap & Friends

  • Moderately powerful (with PhoneGap, can use Camera, Accelerometer, File System, GPS, Notifications)
  • Moderate performance
  • Reasonably familiar (I know HTML etc already)

Am I going to justify using HTML5? The short answer is no. The long answer is that Web technologies are fun and YOLO, so I simply feel like using them. Here we go. Feel free to comment.   

Time to rock 'n' roll - Introducing PhoneGap

Image 3

PhoneGap Build - Build Bot V2 by V2 by Adobe / Yohei Shimomae is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported License.
 

"PhoneGap is an open source framework for quickly building cross-platform mobile apps using HTML5, Javascript and CSS." - http://phonegap.com/about/

Basically, PhoneGap is a native wrapper for web code, allowing web-coded apps to be ported to native apps and distributed in app stores. It supports iOs, Android, WebOS, Windows Phone, Symbian, Bada, and even Blackberry :P. It also gives web apps access to native features like the compass, accelerometer, camera, geolocation, and file system of the target device. It also supports customizable alerts, sounds, and vibrations.

Installing PhoneGap

Here's everything you need (well, for now it's all I've needed) to create native Android apps with HTML5, CSS, and Javascript.

  • If you don't have it already, download and install Node.js.
  • Now, as you can see on this link, open the node.js command line, make sure you are in C:\ directory, and type npm install -g phonegap and hit enter. Let the magic begin!

    Image 4
  • After PhoneGap installs, you will need "Ant". I tried to install Ant myself and failed. I thus highly recommend that you use WinAnt, written by some amazing benefactor out there. WinAnt will do everything for you.
  • Now restart your computer.
  • You now need to configure some environmental variables. Open Control Panel, type "envi" into the search box (all you need) and then click on "Edit the system environmental variables". Now create a new user variable called ANDROID_HOME, set to the path of the folder where you placed your sdk (eg. C:\Users\...\Android\adt-bundle-windows-x86_64-20131030\adt-bundle-windows-x86_64-20131030\sdk). Now edit the PATH variable, appending ";%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools" to it.
  • Restart again. Painful but worth it.
  • You can now create your app. Open the Node.js command line, use the cd command to navigate to where you wish to create your project, and run phonegap create your-app-name.

That's everything installed and our first app created! Start eclipse, and click on the Android SDK Manager icon.

Image 5

Now navigate to Tools>>Manage AVDs. We need to set up a virtual Android device.

Image 6 

Go to the "Device Definitions" tab and choose a device. Originally, I picked Nexus 7 but... 

Image 7

... having used the emulator for a while, I now highly recommend that you use a smaller device, like the Nexus S. The Emulator is pretty slow anyway, but choosing a heavier device can make it unbearably slow.  

Now click "Create AVD...". The device will be setup. After it finishes setting up, return to the command line and run the following commands: cd your-app-name, which moves to your project directory, and phonegap run android, which simultaneously adds android to your project and runs your app on the emulator.  

I took this screenshot of the blank PhoneGap Android app - built from HTML, CSS, and JavaScript!

Image 8 

Before we start...

The www directory

If you open your project's root folder up in File Explorer, you will see a directory called "www". This is the directory that we are going to use and modify (for the most part) to create our app.

A word on developing

Don't do all your debugging and testing in the Android Emulator, it is an incredibly slow process. Compiling an app with PhoneGap can take several minutes, and the Android emulator itself is incredibly slow and rather unresponsive. As a result, I did most of my debugging in desktop Chrome and on a Windows Phone. To do this most effectively, I added this code snippet to the head tag of each page, and removed it whenever I compiled on Android.

HTML
<!--Delete this later-->
<meta name="viewport" content="user-scalable=no, width=device-width"/>
<meta name="msapplication-tap-highlight" content="no" />

Developing my app idea 

Image 9

In this section, I'll go through a brief explanation of how this game works.

Pages

One of the most crucial parts of my game is the Navigation UI. The entire game is run from only one HTML page, the index page, so I divided the HTML into visual "Pages" inside one large container, like this:

HTML
<div id="container" onresize="updateWidths()">
    <div id="header">
        <h1 id="hdrWplText">OcularHues</h1>
        <a href="#" id="hdrButton">Back</a>
    </div>
    
    <div id="Page1" class="Page">
        <div class="content">
            <h2>Total Points Scored</h2>
            <p id="tlt_points"></p>
    	    <div class="menuList">
    		    <ul>
                    <li><a href="#" id="a_unlimited">Play as long as you like...<span class="li_i"><img src="img/arrowright.png"/></span></a></li>
        		    <li><a href="#" id="a_limited">Timelimit (2 mins)...<span class="li_i"><img src="img/arrowright.png"/></span></a></li>
        	    </ul>
        	    <ul>
        	        <li><a href="#" id="a_userstats">Your Stats...<span class="li_i"><img src="img/arrowright.png"/></span></a></li>
        	        <li><a href="#" id="a_about">About...<span class="li_i"><img src="img/arrowright.png"/></span></a></li>
        	    </ul>
    	    </div>
        </div>
    </div>

    <!--Etc-->

</div>

The Pages were defined in CSS like this...

CSS
.Page { position: absolute; display: none; }

And then using Javascript, all Page divs were given the width of the device, and were assigned left=device width, so that all pages would be out of sight on the right of the screen. However, the active page, or the page that the user is using, is caught and set to "display: block" and "left: 0". 

JavaScript
$(document).ready(function () {

    $(".Page").css("top", 46);
    $("#Page5").css("top", 0);

    updateWidths();

    loadPositions();

    $('#hdrButton').click(function (event) {
        event.preventDefault();
        $('#hdrButton').css('background-color', '#C5D4E2');
        slide(previouspage);
    });

}); function loadPositions() {
    //All pages except the root page should be directly off to the right of the screen
    $(".Page").css("left", width());

    $(activepage).css("left", 0);
    $(activepage).css("display", "block");
    $('#hdrButton').css("display", "none"); //It's the home scren. Can't go back.
}

I also animated page tranitions with the code below. This function made moving from page to page was as easy as slide("#PageX")

JavaScript
function unit(pageno) {
    var soFar = $(pageno).css("left").slice(0, -2);

    if (width() / 2 < soFar)
        return width() / 8;
    else
        return Math.pow(soFar, .85);// / 10;
}

function slide(pageno) {
    if (issliding) { return; }
    window.scrollTo(0, 0);
    $(pageno).css("display", "block"); //display the page to the right.
    issliding = true;
    nextIncrement(pageno);
} function nextIncrement(pageno) {
    var current = $(activepage).css("left").slice(0, -2);
    var nextCurrent = current - unit(pageno);
    $(activepage).css("left", nextCurrent.toString() + "px");
    $(pageno).css("left", (nextCurrent + width()).toString() + "px");

    if (nextCurrent + width() < 0 || unit(pageno) < .1) {
        //We're done.
        $(activepage).css("display", "none");
        $(activepage).css("left", width());
        //Change the active page
        activepage = pageno;
        $(activepage).css("left", 0);

        //Page-specific actions
        if (activepage == "#Page1") {
            document.getElementById('hdrWplText').innerHTML = "OcularHues";
            $('#hdrButton').css("display", "none");
        }
        else {
            $('#hdrButton').css("display", "block");
        }
        //etc for each page as needed

        issliding = false;

        if (codeToRunAfterwards != "") {
            var _store = codeToRunAfterwards;
            setTimeout(_store, 1);
            codeToRunAfterwards = "";
        }
    }
    else {
        setTimeout(function () { nextIncrement(pageno) }, 10);
    }
}

The Canvas Element

I used HTML5's canvas element to create this game. It's created programmatically like this:

JavaScript
var view;
var canvas;
$(document).ready(function () {
    //Create the drawing board
    $('#Page5').prepend('<canvas id="view" width="' + width() + '" height="' + height() + '">Your browser does not support the canvas element.</canvas>');
    canvas = document.getElementById("view");
    view = document.getElementById("view").getContext("2d");
});

Creating Dot Colors

The higher the level, the harder it should become to distinguish the dots. This function generates the colors, depending on the level of gameplay.

JavaScript
var R = 255;
var G = 0;
var B = 0;
var mainColor = "";
var adjustedColor = "";
function setGameColors() {
    mainColor = "rgb(" + R + "," + G + "," + B + ")";
    var g = G;
    var b = B;
    var dd = getRandomInt(2, 3);
    isblue = (dd == 3);
    if (dd == 2) { g += (11 - level) * 10; }
    if (dd == 3) { b += (11 - level) * 10; }
    adjustedColor = "rgb(" + R + "," + g + "," + b + ")";
}

One function to rule them all, one function to bind them...

It's ironic that the most important function in the entire game is one of the smallest. This function loops to run the game. 

JavaScript
function runGame() {
    //Update game situation
    UpdateMovements(); //Adjust items on the screen
    DrawGame(); //Visually render the adjusted items unto the screen

    if (is_playing)
        setTimeout("runGame()", 20);
}

Creating the Dots

I could copy and paste more code, but this article is getting long already. Instead, I'll just say that dots' coordinates are stored in arrays, one array for X values and another for Y values. There are actually only 15 normal ("bad") dots, and five unusual off-colored dots. In UpdateMovements(), these dots are moved down the screen at a steady pace, until they are either tapped or they pass through the bottom of the screen, in both of which cases they are re-assigned new X values and placed above the screen a maximum of another device height above the top of the screen, where they resume sliding downwards again.

If you want to see the code, you can always download the source from the top of this article.

Stars

Like the dots, stars have X and Y coordinates stored in arrays. When the game starts, LoopStars() is called, initating the following loop till the end of the game.

JavaScript
function CreateStar() {
    var postY = getRandomInt(-1 * height(), 0);
    var postX = getRandomInt(_r, width() - _r);
    while (overlaps(postX, postY)) {
        postY = getRandomInt(-1 * height(), 0);
        postX = getRandomInt(_r, width() - _r);
    }
    s_X[stars] = postX;
    s_Y[stars] = postY;
    ++stars;
}

function LoopStars() {
    //Skip the very first time.
    if (!first_star)
        CreateStar();

    first_star = false;
    if (is_playing) {
        var wait = getRandomInt(50000, 120000); //50-120 sec
        star_timeout = setTimeout(function () { LoopStars(); }, wait);
    }
}

Adrenaline Mode

I wanted to add something to the game that would break up the monotomy of dots falling down a screen. During Adrenaline Mode, the screen goes purple and speed is increased threefold. Dots tapped during Adrenaline Mode are worth far more than dots tapped during normal game play. Adrenaline Mode is controlled by this loop, initiated with a StartAdrenalineMeter(true):

JavaScript
function doAdrenaline() {
    isadren = true;
    fatfinger = 2; //It's harder to be accurate during adrenaline mode.

    //End it in 10 sec
    var wait = 10000;
    adren_timeout = setTimeout(function () { StartAdrenalineMeter(false); }, wait);
}
function StartAdrenalineMeter(varcheck) {
    if (!varcheck) {
        //Finished
        isadren = false;
        fatfinger = 1.3;
        //Now Start again
        adren_timeout = StartAdrenalineMeter(true);
    }
    else {
        //Start again
        if (is_playing) {
            var wait = getRandomInt(10000, 40000); //10-40 sec
            adren_timeout = setTimeout(function () { doAdrenaline(); }, wait);
        }
    }
}

Creating a Timelimit Mode

We're almost done! Creating a timelimit mode is very easy. I did it by running this code each time the game started playing...

JavaScript
//Let's do this!!
if (istimelimit) {
    d_Date = new Date();
    startTime = d_Date.getTime();
    time_checker = setInterval(function () {
        d_Date = new Date();
        var t_now = d_Date.getTime();
        if (t_now - startTime > 120000) {
            if (navigator.notification) {
                navigator.notification.alert("Two minutes have elapsed.", null, "Time's Up!", "OK");
            } else {
                alert("Time's Up! Two minutes have elapsed.");
            }
            QuitGame();
        }
    }, 5000);
}

Storing User Stats

I won't copy and paste all of the code that went into this part of the app, but I will demonstrate with a very basic example how I did it.

I used a new HTML5 feature called Localstorage. Localstorage is used like this:

JavaScript
if (!localstorage.stored)
{
    localstorage.foobar = 10;
    localstorage.stored = "true";
}
else
{
    alert(localstorage.foobar);
}

//Imagaine the page closes. Then the user opens it again...
//<--Imagining--->
//Result: 10

So keeping user stats was as easy as monitoring points and taps, and storing these in localstorage. Again, if you want the full code, you can always download the source. :-) 

Publishing

That's the code done! Time to sign and publish...

  • Open config.xml in the www directory, and update the details in there. My app id is app.lufroloc.ocularhues (lufroloc is colorful backwards). Save.
  • In your project directory, navigate to the platforms/android directory and open AndroidManifest.xml
  • Set android:debuggable to false.

    Image 10
  • Save. Remember the Android Project we created a the very start of this article - in the Android IDE? Open it up again in Eclipse.
  • In Package Explorer, on the right side of your screen, right-click on your project directory
  • Now Android Tools>>Export Signed Application Package
  • Follow the steps through to create a keystore and a key. You'll need these to sign your app.
  • Make sure that you keep your passwords and alias name! You'll need them to update your app, and also to sign it!
  • Now go to build.phonegap.com, and sign in or create an account.
  • When asked to upload a .zip file, compress your entire project directory (not just the www folder) and upload it.
  • PhoneGap's website will take it from there. It's pretty intuitive. Once you're done, you should be able to download your compiled and signed APK file.

Known Issues:

I'm aware of some problems with my app at the moment. If you find any more, feel free to post below :-)

  • Performance bad on emulator.
    I'm not sure how much of this is my app and how much is the emulator. The emulator is horrifically slow on its own... so I'd have a better idea of real performance if I had a chance to run my app on an actual device.
  • Sounds not working.
    For some strange reason the sounds don't seem to be working in the app

Wrapping Up

That's it! Thanks for staying with me! I hope you enjoyed my Android submission. If you have an Android, feel free to install my app (downloadable in a .zip from the top of this page). Any feedback will be greatly appreciated. :-)

History

  • 23/12/2013 - First version. 
  • 28/12/2013 - Second version. Created an alpha edition of this game. 
  • 31/12/2013 - Third version. Finished the app, at least for now.
  • 13/01/2014 - Fixed a few typos, polished the text a bit. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)