lufy 发表于 2013-4-10 09:59:24

用HTML5来开发一款android本地化App游戏-宝石碰碰

本次来说一说如何利用lufylegend.js引擎制作一款HTML5游戏后,将其转换为android本地化的App应用,转换过程其实很简单,下面一步步来做说明。首先来开发一个类似于对对碰的游戏,不过此游戏玩法为在下原创,如有雷同,纯属巧合,游戏界面如下。http://lufylegend.com/lufylegend_blog_img/jpg/17.jpg
游戏操作:上下左右划动屏幕,来操作宝石向不同的方向移动。游戏规则:当有三个一样的宝石相邻则消除,被消除过一次的宝石会变成半透明,当所有宝石都被消除一次后,则进入下一关。游戏测试连接:http://lufylegend.com/demo/GemGem
制作开始一,准备首先,需要下载lufylegend.js引擎,下面是我在博客的lufylegend-1.7.0发布帖http://blog.csdn.net/lufy_legend/article/details/8719768
二,游戏开发引擎lufylegend1.7.0中扩展了LLoadManage静态类,可以读取图片,js文件以及文本文件,本次游戏开发就来体验一下这个新功能,首先看下面数组代码清单1var loadData = [
{path:"../jquery.js",type:"js"},
{path:"./js/share.js",type:"js"},
{path:"./js/Social.js",type:"js"},
{path:"./js/GameRanking.js",type:"js"},
{path:"./js/GameLogo.js",type:"js"},
{path:"./js/GameClear.js",type:"js"},
{path:"./js/Gem.js",type:"js"},
{path:"./js/Stage.js",type:"js"},
{path:"./js/Clock.js",type:"js"},
{path:"./js/Point.js",type:"js"},
{path:"./js/GetPoint.js",type:"js"},
{path:"./js/Bullet.js",type:"js"},
{path:"./js/Event.js",type:"js"},
{path:"./js/function.js",type:"js"},
{path:"./js/GameBody.js",type:"js"},
{name:"num.+",path:"./images/plus.png"},
{name:"num.0",path:"./images/0.png"},
{name:"num.1",path:"./images/1.png"},
{name:"num.2",path:"./images/2.png"},
{name:"num.3",path:"./images/3.png"},
{name:"num.4",path:"./images/4.png"},
{name:"num.5",path:"./images/5.png"},
{name:"num.6",path:"./images/6.png"},
{name:"num.7",path:"./images/7.png"},
{name:"num.8",path:"./images/8.png"},
{name:"num.9",path:"./images/9.png"},
{name:"back",path:"./images/back.png"},
{name:"line",path:"./images/line.png"},
{name:"clear",path:"./images/clear.png"},
{name:"gem01",path:"./images/gem01.png"},
{name:"gem02",path:"./images/gem02.png"},
{name:"gem03",path:"./images/gem03.png"},
{name:"gem04",path:"./images/gem04.png"},
{name:"gem05",path:"./images/gem05.png"},
{name:"gem06",path:"./images/gem06.png"},
{name:"gem07",path:"./images/gem07.png"},
{name:"gem08",path:"./images/gem08.png"},
{name:"gem09",path:"./images/gem09.png"},
{name:"ico_sina",path:"./images/ico_sina.gif"},
{name:"ico_qq",path:"./images/ico_qq.gif"},
{name:"ico_facebook",path:"./images/ico_facebook.png"},
{name:"ico_twitter",path:"./images/ico_twitter.png"}
];将需要的js文件和图片文件都加到数组内,如果需要加载文件为js文件时,需要指定type为js,如果加载的文件为图片,则type可以不设定。
读取过程与之前用法完全一样代码清单2function main(){
        loadingLayer = new LoadingSample3();
        addChild(loadingLayer);       
        LLoadManage.load(
                loadData,
                function(progress){
                        loadingLayer.setProgress(progress);
                },
                function(result){
                        LGlobal.setDebug(true);
                        datalist = result;
                        removeChild(loadingLayer);
                        loadingLayer = null;
                        gameInit();
                }
        );
}下面来向游戏中添加8行8列64块宝石,具体做法如下代码清单3function addGem(){
        stage.setStage(stage.num + 1);
        gemLayer.removeAllChild();
        list = [];
        //添加宝石
        for(i=0;i<8;i++){
                list.push([]);
                for(var j=0;j<8;j++){
                        num = (Math.random()*9 >>> 0)+1;
                        g = new Gem(num);
                        g.x = j*60;
                        g.y = i*60+120;
                        gemLayer.addChild(g);
                        list.push(g);
                }
        }
        //检验可消除宝石
        do{
                clearList = checkClear();
                if(clearList.length > 0){
                        for(i=0;i<clearList.length;i++){
                                g = clearList;
                                num = (Math.random()*9 >>> 0)+1;
                                g.change(num);
                        }
                }
        }while(clearList.length > 0);
}上面代码中的Gem对象是一个宝石类,完整代码如下代码清单4function Gem(num){
        var self = this;
        base(self,LSprite,[]);
        self.num = num;
        self.bitmap = new LBitmap(new LBitmapData(datalist["gem0"+num]));
        self.bitmap.x=self.bitmap.y=10;
        self.addChild(self.bitmap);
       
}
Gem.prototype.change = function (num){
        var self = this;
        self.num = num;
        self.bitmap.bitmapData = new LBitmapData(datalist["gem0"+num]);
}Gem类继承自LSprite,内部包含一个LBitmap对象来显示宝石图片。代码清单3中调用了checkClear函数,来检验是否有可消除宝石,检测方法为先进行横向检索,然后进行纵向检索。代码清单5clearList = [];
        //横向检索
        for(i=0;i<8;i++){
                checkList = ];
                for(j=1;j<8;j++){
                        if(checkList.num == list.num){
                                checkList.push(list);
                        }else{
                                clearList = addClearList(clearList,checkList);
                                checkList = ];
                        }
                }
                clearList = addClearList(clearList,checkList);
        }
        //纵向检索
        for(i=0;i<8;i++){
                checkList = ];
                for(j=1;j<8;j++){
                        if(checkList.num == list.num){
                                checkList.push(list);
                        }else{
                                clearList = addClearList(clearList,checkList);
                                checkList = ];
                        }
                }
                clearList = addClearList(clearList,checkList);
        }addClearList函数作用是将可消除宝石压入clearList数组,做法如下
代码清单6function addClearList(clearList,checkList){
        if(checkList.length >= 3){
                clearList = clearList.concat(checkList)
        }
        return clearList;
}游戏操作需要划动屏幕,但是在lufylegend.js引擎中,是没有划动屏幕的事件的,所以我通过下面MOUSE_DOWN,MOUSE_UP获取点击时和点击后的位置,来模拟一下划动事件。
代码清单7        backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onDown);
        backLayer.addEventListener(LMouseEvent.MOUSE_UP,onUp);再来看看具体做法,先是onDown函数。代码清单8function onDown(e){
        if(mouse_down_obj.isMouseDown)return;
        continuous = 0;
        mouse_down_obj.x = e.offsetX;
        mouse_down_obj.y = e.offsetY;
        mouse_down_obj.time = new Date().getTime();
        mouse_down_obj.cx = e.offsetX/60 >>> 0;
        mouse_down_obj.cy = (e.offsetY - 120)/60 >>> 0;
        mouse_down_obj.isMouseDown = true;
        list.graphics.drawRect(1,"black",,true,"#000000");
}通过e.offsetX和e.offsetY来获取点击位置,通过getTime()来获取点击时刻的时间。
在来看看onUp函数。代码清单9function onUp(e){
        list.graphics.clear();
        if(new Date().getTime() - mouse_down_obj.time > 500){
                mouse_down_obj.isMouseDown = false;
                return;
        }
        var mx = e.offsetX - mouse_down_obj.x;
        var my = e.offsetY - mouse_down_obj.y;
        if(Math.abs(mx) > Math.abs(my)){
                if(mx > 50){
                        move("right");
                        return;
                }else if(mx < -50){
                        move("left");
                        return;
                }
        }else{
                if(my > 50){
                        move("down");       
                        return;
                }else if(my < -50){
                        move("up");
                        return;
                }
        }
        mouse_down_obj.isMouseDown = false;
}函数中通过同样的方法得到点击结束时的位置和时间,然后与点击时刻做比较,最后计算划动的方向,然后根据划动的方向来调用move函数,让宝石移动。
move函数如下:
代码清单10function move(dir){
        direction = dir;
        var m = moveGem(dir,8);
        var mx = m,my = m;
        var obj,fun;
        for(var i=0;i<8;i++){
                if(mx == 0){
                        obj = list;
                }else{
                        obj = list;
                }
                if(i < 7){
                        fun = null;
                }else{
                        fun = function(){
                                hiddenObj.visible = true;
                                checkClear();
                        };
                }
                LTweenLite.to(obj,0.3,
                {
                        x:obj.x+mx,
                        y:obj.y+my,
                        onComplete:fun,
                        ease:Strong.easeOut
                });
       
        }
}下面以向右移动为例来说明一下move函数的处理过程,如下
http://lufylegend.com/lufylegend_blog_img/jpg/21.jpg

先将最左边的一个宝石H移到最左边,然后再利用LTweenLite缓动类将整个一行8个宝石,向右缓动一个单位。向左的话正好相反,向上向下也是同样的原理。每次缓动结束,要调用一次checkClear函数,来判断一下是否有可消除的宝石,如果有则开始消除宝石,如何来消除宝石呢?我依然以向右划动来举例说明,看下面图片,假设D1,D2,D3可消除,E4,F4,G4可消除http://lufylegend.com/lufylegend_blog_img/jpg/27.jpg

那么首先将D1,D2,D3移到左边边界外,E4,F4,G4也移到边界外,表示被消除,之后对每一行的宝石进行位置判定,如每行的第一个宝石的x坐标应该是60,第二个为120,以此类推。如果他们不在自己的相应位置上,那么将其向左移动到规定位置就可以了,写成代码的话,如下。
代码清单11function moveList(){
        var gem,time,maxTime,mx,my,fun;
        maxTime = 0;
        switch(direction){
                case "left":
                        for(i=0;i<8;i++){
                                for(j=0;j<8;j++){
                                        gem = list;
                                        mx = 60*j;
                                        if(gem.x > mx){
                                                time = 0.3*((gem.x-mx) / 60 >>> 0);
                                                if(maxTime < time)maxTime = time;
                                                fun = null;
                                                if(gem.x > 420){
                                                        fun = function(gem){
                                                                if(gem.x <= 420)gem.visible = true;
                                                        }
                                                }
                                                LTweenLite.to(gem,time,
                                                {
                                                        x:mx,
                                                        onUpdate:fun,
                                                        onComplete:fun,
                                                        ease:Strong.easeOut
                                                });
                                        }
                                }
                        }
                        break;
                case "right":
                        for(i=0;i<8;i++){
                                for(j=0;j<8;j++){
                                        gem = list;
                                        mx = 60*j;
                                        if(gem.x < mx){
                                                time = 0.3*((mx-gem.x) / 60 >>> 0);
                                                if(maxTime < time)maxTime = time;
                                                fun = null;
                                                if(gem.x < 0){
                                                        fun = function(gem){
                                                                if(gem.x >= 0)gem.visible = true;
                                                        }
                                                }
                                                LTweenLite.to(gem,time,
                                                {
                                                        x:mx,
                                                        onUpdate:fun,
                                                        onComplete:fun,
                                                        ease:Strong.easeOut
                                                });
                                        }
                                }
                        }
                        break;
                case "up":
                        for(i=0;i<8;i++){
                                for(j=0;j<8;j++){
                                        gem = list;
                                        my = 120+60*j;
                                        if(gem.y > my){
                                                time = 0.3*((gem.y-my) / 60 >>> 0);
                                                if(maxTime < time)maxTime = time;
                                                fun = null;
                                                if(gem.y > 560){
                                                        fun = function(gem){
                                                                if(gem.y <= 560)gem.visible = true;
                                                        }
                                                }
                                                LTweenLite.to(gem,time,
                                                {
                                                        y:my,
                                                        onUpdate:fun,
                                                        onComplete:fun,
                                                        ease:Strong.easeOut
                                                });
                                        }
                                }
                        }
                        break;
                case "down":
                        for(i=0;i<8;i++){
                                for(j=0;j<8;j++){
                                        gem = list;
                                        my = 120+60*j;
                                        if(gem.y < my){
                                                time = 0.3*((my-gem.y) / 60 >>> 0);
                                                if(maxTime < time)maxTime = time;
                                                fun = null;
                                                if(gem.y < 120){
                                                        fun = function(gem){
                                                                if(gem.y >= 120)gem.visible = true;
                                                        }
                                                }
                                                LTweenLite.to(gem,time,
                                                {
                                                        y:my,
                                                        onUpdate:fun,
                                                        onComplete:fun,
                                                        ease:Strong.easeOut
                                                });
                                        }
                                }
                        }
                        break;
        }
        LTweenLite.to({},maxTime*1.5,
        {
                onComplete:checkStageClear,
                ease:Strong.easeOut
        });
}当然,游戏是有时间限制的,看下面的Clock类。代码清单12function Clock(){
        var self = this;
        base(self,LSprite,[]);
        self.timer = 0;
        self.addTimer = 0.05;
        self.graphics.drawArc(5,"#333333",);
       
}
Clock.prototype.onframe = function (){
        var self = this;
        self.timer += self.addTimer;
        self.graphics.clear();
        self.graphics.drawArc(10,"#333333",);
        self.graphics.drawArc(5,"#ffffff",);
}首先将Clock加载到游戏中,然后再利用ENTER_FRAME时间轴事件,来不断调用Clock的onframe不断的绘制圆弧,当timer的数值大于等于360的时候代表画完了整个圆弧,那么游戏结束。
以上,游戏的主要原理都介绍完了,下面看看如何来把游戏转化为本地App三,发布本地化App首先,用Eclipse新建一个Android Projecthttp://lufylegend.com/lufylegend_blog_img/jpg/23.jpg

注:如何搭建Android环境,我就不说了,网上教程多得是,随便百度一下吧。然后,填写项目名称,并选择相应的sdk版本,这里我选了2.2http://lufylegend.com/lufylegend_blog_img/jpg/24.jpg
接着是填写相应数据,这个随自己心情就可以了。http://lufylegend.com/lufylegend_blog_img/jpg/25.jpg
接着,重点来了,在工程下的assets文件夹下,简历一个www文件夹(名字自己随意),然后把刚才开发好的游戏复制到这个文件夹下,当然,lufylegend引擎也必须复制过来。http://lufylegend.com/lufylegend_blog_img/jpg/26.jpg
接着修改res/layout/main.xml文件,添加webView,如下<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>最后,修改Main.java文件,利用webView来显示html网页,如下public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        WebView webview = (WebView )findViewById(R.id.webView1);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.setVerticalScrollbarOverlay(true);
        webview.loadUrl("file:///android_asset/www/index.html");
    }
}好了,运行程序吧。
http://lufylegend.com/lufylegend_blog_img/jpg/28.jpg
画面如下:http://lufylegend.com/lufylegend_blog_img/jpg/22.jpg
最后,想要发布游戏为.apk文件的话,build一下就好了。http://lufylegend.com/lufylegend_blog_img/jpg/29.jpg发布后的apk文件。
http://lufylegend.com/lufylegend_blog_img/jpg/30.jpg
结束了,简单吧?四,源码最后给出本次游戏的源代码http://lufylegend.com/lufylegend_download/GemGem.rar
注:只含游戏源码,lufylegend.js引擎请自己到官网下载

erhkhr462 发表于 2014-5-9 17:25:57

看帖子的要发表下看法

jack_liu 发表于 2014-5-10 19:49:53

嘿嘿  跟站长一伙的啊

731315163 发表于 2015-11-13 20:09:20

电脑浏览器玩不了

lufy 发表于 2015-11-13 20:24:49

731315163 发表于 2015-11-13 20:09 static/image/common/back.gif
电脑浏览器玩不了

这个帖子的代码太久了,用最新版本引擎下的demo

serajes 发表于 2024-3-18 15:22:18

本帖最后由 serajes 于 2024-3-18 15:29 编辑

Textfree is available for both iOS and Android devices and free text and call app without phone number. offers both free and paid versions with additional features.
页: [1]
查看完整版本: 用HTML5来开发一款android本地化App游戏-宝石碰碰