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.
- 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
"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!
- 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.
Now navigate to Tools>>Manage AVDs. We need to set up a virtual Android device.
Go to the "Device Definitions" tab and choose a device. Originally, I picked Nexus 7 but...
... 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!
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.
<!--
<meta name="viewport" content="user-scalable=no, width=device-width"/>
<meta name="msapplication-tap-highlight" content="no" />
Developing my app idea
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:
<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>
<!--
</div>
The Pages were defined in CSS like this...
.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".
$(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() {
$(".Page").css("left", width());
$(activepage).css("left", 0);
$(activepage).css("display", "block");
$('#hdrButton').css("display", "none");
}
I also animated page tranitions with the code below. This function made moving from page to page was as easy as slide("#PageX")
.
function unit(pageno) {
var soFar = $(pageno).css("left").slice(0, -2);
if (width() / 2 < soFar)
return width() / 8;
else
return Math.pow(soFar, .85);
}
function slide(pageno) {
if (issliding) { return; }
window.scrollTo(0, 0);
$(pageno).css("display", "block");
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) {
$(activepage).css("display", "none");
$(activepage).css("left", width());
activepage = pageno;
$(activepage).css("left", 0);
if (activepage == "#Page1") {
document.getElementById('hdrWplText').innerHTML = "OcularHues";
$('#hdrButton').css("display", "none");
}
else {
$('#hdrButton').css("display", "block");
}
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:
var view;
var canvas;
$(document).ready(function () {
$('#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.
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.
function runGame() {
UpdateMovements();
DrawGame();
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.
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() {
if (!first_star)
CreateStar();
first_star = false;
if (is_playing) {
var wait = getRandomInt(50000, 120000);
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)
:
function doAdrenaline() {
isadren = true;
fatfinger = 2;
var wait = 10000;
adren_timeout = setTimeout(function () { StartAdrenalineMeter(false); }, wait);
}
function StartAdrenalineMeter(varcheck) {
if (!varcheck) {
isadren = false;
fatfinger = 1.3;
adren_timeout = StartAdrenalineMeter(true);
}
else {
if (is_playing) {
var wait = getRandomInt(10000, 40000);
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...
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:
if (!localstorage.stored)
{
localstorage.foobar = 10;
localstorage.stored = "true";
}
else
{
alert(localstorage.foobar);
}
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
.
- 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.