65.9K
CodeProject 正在变化。 阅读更多。
Home

Android vs. CraigDJ

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (24投票s)

2013年12月23日

CPOL

11分钟阅读

viewsIcon

59080

downloadIcon

1258

我使用HTML5、CSS、Javascript、Node.js和PhoneGap创建了一个Android游戏,这是我的开发过程。

介绍 

大家好,欢迎来到我的Android应用项目! 

我必须承认,我对原生Android环境几乎一无所知——这是我鲁莽地 dive 到CP的Android版块。我没有去学习一个全新的环境和语言,而是使用HTML5、CSS和Javascript构建了我的游戏,并通过一个名为PhoneGap的开源项目将其移植到Android。随着项目的进展,我一直在更新这篇文章——请继续关注,不要忘了投票和评论!

我的应用想法是什么? 

如今,我们的LCD显示器可以显示数百万种颜色,而我们的眼睛也能感知数百万种颜色。我设想了一个极致测试人眼的简单游戏。

有几种方法可以做到这一点,但我脑海中最先浮现的是一种计算机生成的点在屏幕上滑动的画面。想象一下,几乎所有的点都颜色相同,只有少数几个点会被应用程序通过添加或减少一点R、G或B值而略微修改。用户的目标是点击那些颜色不同的点(也许可以将它们滑到屏幕的边缘)。

可以创建几种游戏模式——限时模式、在线模式(与其他玩家对战)、无限玩模式(赚取积分和道具)以及多色模式(增加难度)。

用户可以自定义基础颜色。点还可以与音乐同步。

应用程序可以跟踪用户最擅长识别哪种颜色修改,并在用户个人资料中显示这些信息,以供用户参考。游戏中有几种可收集物品(与点一起下落的物品):颜色增强器(使识别差异更容易)、积分、炸弹(不要收集这些!)以及临时减速。

设置 

我是一个坦白的Android新手。假设你也是,以下是你开始所需的一切。 

  • 你需要一个Java开发工具包(JDK)。在此处下载并安装
    如果你还没有,这个工具包也包含一个完整的JRE。
  • 下载并安装Android SDK。SDK没有安装程序,所以我建议你创建一个新文件夹来存放SDK文件(例如,放在Program Files中,或与你的文档/图片/视频旁边)。
  • 而且,如果你还没有,我推荐安装GIMP,一个免费且功能强大的图像编辑器。我用它来创建游戏中的一些图形。

查看原生SDK

现在你应该拥有开发Android所需的一切了。现在和我一起花点时间看看SDK,感受一下。

  • 打开Eclipse(双击/eclipse/eclipse.exe)。
  • 导航到File>>New>>Android Application Project并点击。

  • 一路按默认设置完成。
  • 你可以连接你的Android设备(如果你有的话),并在上面运行你的第一个应用。我没有Android设备,所以没有执行这一步。

这时,在我的应用进展到这一步时我停了下来。学习一个全新的环境和语言突然变得太过痛苦。我拥有设备,但不知道如何使用它。 

HTML5?Node.js?这是什么...?

我真的不想为了写这个应用而学习原生Android开发。我知道可以使用Web技术来构建应用,于是我决定探索这条路。我仍然学到了很多,只是过程没那么痛苦!

以下是对比

原生环境

  • 功能极其强大
  • 性能优越
  • 完全不熟悉(IDE、语言,一切都是新的)

PhoneGap & Friends

  • 功能适中(使用PhoneGap,可以使用摄像头、加速计、文件系统、GPS、通知)
  • 性能适中
  • 相对熟悉(我已经知道HTML等)

我需要证明使用HTML5的理由吗?简短的回答是“不需要”。长长的回答是,Web技术很有趣,而且YOLO(活在当下),所以我就是想用它们。现在开始。欢迎评论。   

开始吧——介绍PhoneGap

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

“PhoneGap是一个开源框架,可以利用HTML5、Javascript和CSS快速构建跨平台移动应用。”——http://phonegap.com/about/

基本上,PhoneGap是一个原生的Web代码包装器,它允许用Web代码编写的应用被移植到原生应用并在应用商店分发。它支持iOS、Android、WebOS、Windows Phone、Symbian、Bada,甚至Blackberry :P。它还允许Web应用访问目标设备的本地功能,如指南针、加速计、摄像头、地理位置和文件系统。它还支持自定义警报、声音和振动。

安装PhoneGap

这是创建原生Android应用所需的一切(至少目前我只需要这些)——使用HTML5、CSS和Javascript。

  • 如果你还没有,请下载并安装Node.js
  • 现在,正如你在这个链接上看到的,打开Node.js命令行,确保你在C:\目录下,然后输入npm install -g phonegap并按回车键。让魔法开始!

  • PhoneGap安装后,你需要“Ant”。我尝试自己安装Ant但失败了。因此,我强烈建议你使用WinAnt,它是由某个神奇的贡献者编写的。WinAnt将为你处理一切。
  • 现在重启你的电脑。
  • 现在你需要配置一些环境变量。打开控制面板,在搜索框中输入“envi”(只需输入这些),然后点击“编辑系统环境变量”。现在创建一个名为ANDROID_HOME的新用户变量,将其值设置为你存放SDK的文件夹路径(例如,C:\Users\...\Android\adt-bundle-windows-x86_64-20131030\adt-bundle-windows-x86_64-20131030\sdk)。现在编辑PATH变量,在后面追加“;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools”。
  • 再次重启。虽然痛苦,但值得。
  • 现在你可以创建你的应用了。打开Node.js命令行,使用cd命令导航到你想要创建项目的目录,然后运行phonegap create your-app-name

这样就安装好了所有东西,并且创建了我们的第一个应用!启动Eclipse,然后点击Android SDK Manager图标。

现在导航到Tools>>Manage AVDs。我们需要设置一个虚拟Android设备。

 

转到“Device Definitions”选项卡并选择一个设备。最初,我选择了Nexus 7,但是...

...在使用模拟器一段时间后,我现在强烈建议你使用较小的设备,比如Nexus S。模拟器本身已经相当慢了,选择一个较重的设备可能会让它慢得无法忍受。  

现在点击“Create AVD...”。设备将被设置。设置完成后,返回到命令行并运行以下命令:cd your-app-name,这会进入你的项目目录,然后运行phonegap run android,这会同时将Android添加到你的项目中并在模拟器上运行你的应用。  

这张截图是我用HTML、CSS和JavaScript构建的空白PhoneGap Android应用!

 

在我们开始之前...

www目录

如果你在文件资源管理器中打开项目的根文件夹,你会看到一个名为“www”的目录。这个目录是我们(在很大程度上)将要用来创建应用的。

关于开发的一点说明

不要在Android模拟器上完成所有的调试和测试,这是一个非常缓慢的过程。使用PhoneGap编译一个应用可能需要几分钟,而Android模拟器本身就非常慢,而且相当不响应。因此,我大部分的调试工作都是在桌面Chrome和Windows Phone上完成的。为了最有效地做到这一点,我将这段代码片段添加到了每个页面的head标签中,并在编译Android版本时将其移除。

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

开发我的应用想法 

在本节中,我将简要解释这个游戏是如何工作的。

页数

我游戏中最关键的部分之一是导航UI。整个游戏只在一个HTML页面(index页面)上运行,所以我将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>

页面是这样在CSS中定义的...

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

然后使用Javascript,所有Page div都被设置为设备的宽度,并且它们的left属性被设置为device width,这样所有的页面都会在屏幕的右侧不可见。但是,活动页面,即用户正在使用的页面,会被捕获并设置为“display: block”和“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() {
    //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.
}

我还用下面的代码动画化了页面过渡。这个函数使得从一个页面移动到另一个页面就像调用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);// / 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);
    }
}

Canvas元素

我使用了HTML5的canvas元素来创建这个游戏。它是以这种方式以编程方式创建的

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");
});

创建点颜色

关卡越高,区分点的难度应该越大。这个函数根据游戏关卡生成颜色。

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 + ")";
}

一个函数统治一切,一个函数把它们联系起来...

很有讽刺意味的是,整个游戏中最重要的函数之一却是最小的。这个函数循环运行游戏。 

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);
}

创建点

我可以复制粘贴更多的代码,但这篇文章已经很长了。相反,我只想说,点的坐标存储在数组中,一个数组存储X值,另一个数组存储Y值。实际上只有15个正常的(“坏”)点,以及五个不寻常的、颜色不同的点。在UpdateMovements()中,这些点以稳定的速度向下移动,直到它们被点击或穿过屏幕底部。在这两种情况下,它们都会被重新分配新的X值,并放置在屏幕上方,最多比屏幕顶部高一个设备高度,然后它们将再次开始向下滑动。

如果你想看代码,随时可以从本文顶部下载源代码。

星星

与点一样,星星的X和Y坐标也存储在数组中。当游戏开始时,会调用LoopStars(),直到游戏结束,它会启动以下循环。

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);
    }
}

肾上腺素模式

我想在游戏中增加一些东西来打破点在屏幕上滚动的单调。在肾上腺素模式期间,屏幕会变成紫色,速度会增加三倍。在肾上腺素模式期间点击的点比正常游戏玩法中点击的点值钱得多。肾上腺素模式由这个循环控制,通过StartAdrenalineMeter(true)启动。

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);
        }
    }
}

创建限时模式

我们快完成了!创建限时模式非常容易。每次游戏开始时,我都通过运行这段代码来做到这一点...

//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);
}

存储用户统计数据

我不会复制粘贴所有用于这部分应用的代码,但我会用一个非常基本的例子来展示我是如何做到的。

我使用了一个新的HTML5功能,称为Localstorage。Localstorage的使用方式如下

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

所以,保存用户统计数据就像监控积分和点击次数一样简单,并将这些数据存储在localstorage中。同样,如果你想要完整的代码,随时可以下载源代码。:-)  

出版

代码就完成了!现在是签名和发布时间...

  • 打开www目录下的config.xml,并更新其中的详细信息。我的应用ID是app.lufroloc.ocularhues(lufroloc是colorful的倒序)。保存。
  • 在你的项目目录中,导航到platforms/android目录并打开AndroidManifest.xml
  • android:debuggable设置为false

  • 保存。还记得本文开头我们在Android IDE中创建的Android项目吗?在Eclipse中再次打开它。
  • 在Package Explorer中,屏幕右侧,右键单击你的项目目录。
  • 然后选择Android Tools>>Export Signed Application Package。
  • 按照步骤创建一个密钥库和密钥。你需要它们来签名你的应用。
  • 确保你记住了密码和别名!更新和签名应用时都需要它们!
  • 现在去build.phonegap.com,登录或创建一个账户。
  • 当被要求上传.zip文件时,压缩你的整个项目目录(不仅仅是www文件夹),然后上传。
  • PhoneGap的网站会处理接下来的事情。它相当直观。完成后,你应该就能下载编译和签名的APK文件了。

已知问题

我知道我的应用目前存在一些问题。如果你发现更多问题,请随时在下方评论:-)

  • 模拟器性能不佳。
    我不确定这有多大程度上是我的应用的问题,有多大程度上是模拟器的问题。模拟器本身已经非常慢了……所以如果我能在实际设备上运行我的应用,我会对真实性能有更好的了解。
  • 声音不工作。
    不知何故,应用中的声音似乎不起作用。

总结

就是这样!感谢你一直以来的支持!希望你喜欢我的Android提交。如果你有Android设备,请随时安装我的应用(可以从页面顶部下载.zip文件)。任何反馈都将不胜感激。:-)

历史

  • 2013/12/23 - 第一个版本。 
  • 2013/12/28 - 第二个版本。创建了游戏的alpha版本。 
  • 2013/12/31 - 第三个版本。至少目前完成了应用。
  • 2014/01/13 - 修复了一些拼写错误,润色了文本。 
© . All rights reserved.