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

本次来说一说如何利用lufylegend.js引擎制作一款HTML5游戏后,将其转换为android本地化的App应用,转换过程其实很简单,下面一步步来做说明。

首先来开发一个类似于对对碰的游戏,不过此游戏玩法为在下原创,如有雷同,纯属巧合,游戏界面如下

游戏操作:上下左右划动屏幕,来操作宝石向不同的方向移动。

游戏规则:当有三个一样的宝石相邻则消除,被消除过一次的宝石会变成半透明,当所有宝石都被消除一次后,则进入下一关。

游戏测试连接:

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文件以及文本文件,本次游戏开发就来体验一下这个新功能,首先看下面数组

代码清单1

 

[javascript] view plaincopy
 
  1. var loadData = [  
  2. {path:"../jquery.js",type:"js"},  
  3. {path:"./js/share.js",type:"js"},  
  4. {path:"./js/Social.js",type:"js"},  
  5. {path:"./js/GameRanking.js",type:"js"},  
  6. {path:"./js/GameLogo.js",type:"js"},  
  7. {path:"./js/GameClear.js",type:"js"},  
  8. {path:"./js/Gem.js",type:"js"},  
  9. {path:"./js/Stage.js",type:"js"},  
  10. {path:"./js/Clock.js",type:"js"},  
  11. {path:"./js/Point.js",type:"js"},  
  12. {path:"./js/GetPoint.js",type:"js"},  
  13. {path:"./js/Bullet.js",type:"js"},  
  14. {path:"./js/Event.js",type:"js"},  
  15. {path:"./js/function.js",type:"js"},  
  16. {path:"./js/GameBody.js",type:"js"},  
  17. {name:"num.+",path:"./images/plus.png"},  
  18. {name:"num.0",path:"./images/0.png"},  
  19. {name:"num.1",path:"./images/1.png"},  
  20. {name:"num.2",path:"./images/2.png"},  
  21. {name:"num.3",path:"./images/3.png"},  
  22. {name:"num.4",path:"./images/4.png"},  
  23. {name:"num.5",path:"./images/5.png"},  
  24. {name:"num.6",path:"./images/6.png"},  
  25. {name:"num.7",path:"./images/7.png"},  
  26. {name:"num.8",path:"./images/8.png"},  
  27. {name:"num.9",path:"./images/9.png"},  
  28. {name:"back",path:"./images/back.png"},  
  29. {name:"line",path:"./images/line.png"},  
  30. {name:"clear",path:"./images/clear.png"},  
  31. {name:"gem01",path:"./images/gem01.png"},  
  32. {name:"gem02",path:"./images/gem02.png"},  
  33. {name:"gem03",path:"./images/gem03.png"},  
  34. {name:"gem04",path:"./images/gem04.png"},  
  35. {name:"gem05",path:"./images/gem05.png"},  
  36. {name:"gem06",path:"./images/gem06.png"},  
  37. {name:"gem07",path:"./images/gem07.png"},  
  38. {name:"gem08",path:"./images/gem08.png"},  
  39. {name:"gem09",path:"./images/gem09.png"},  
  40. {name:"ico_sina",path:"./images/ico_sina.gif"},  
  41. {name:"ico_qq",path:"./images/ico_qq.gif"},  
  42. {name:"ico_facebook",path:"./images/ico_facebook.png"},  
  43. {name:"ico_twitter",path:"./images/ico_twitter.png"}  
  44. ];  

将需要的js文件和图片文件都加到数组内,如果需要加载文件为js文件时,需要指定type为js,如果加载的文件为图片,则type可以不设定。

 

读取过程与之前用法完全一样

代码清单2

 

[javascript] view plaincopy
 
  1. function main(){  
  2.     loadingLayer = new LoadingSample3();  
  3.     addChild(loadingLayer);   
  4.     LLoadManage.load(  
  5.         loadData,  
  6.         function(progress){  
  7.             loadingLayer.setProgress(progress);  
  8.         },  
  9.         function(result){  
  10.             LGlobal.setDebug(true);  
  11.             datalist = result;  
  12.             removeChild(loadingLayer);  
  13.             loadingLayer = null;  
  14.             gameInit();  
  15.         }  
  16.     );  
  17. }  

下面来向游戏中添加8行8列64块宝石,具体做法如下

代码清单3

[javascript] view plaincopy
 
  1. function addGem(){  
  2.     stage.setStage(stage.num + 1);  
  3.     gemLayer.removeAllChild();  
  4.     list = [];  
  5.     //添加宝石  
  6.     for(i=0;i<8;i++){  
  7.         list.push([]);  
  8.         for(var j=0;j<8;j++){  
  9.             num = (Math.random()*9 >>> 0)+1;  
  10.             g = new Gem(num);  
  11.             g.x = j*60;  
  12.             g.y = i*60+120;  
  13.             gemLayer.addChild(g);  
  14.             list[i].push(g);  
  15.         }  
  16.     }  
  17.     //检验可消除宝石  
  18.     do{  
  19.         clearList = checkClear();  
  20.         if(clearList.length > 0){  
  21.             for(i=0;i<clearList.length;i++){  
  22.                 g = clearList[i];  
  23.                 num = (Math.random()*9 >>> 0)+1;  
  24.                 g.change(num);  
  25.             }  
  26.         }  
  27.     }while(clearList.length > 0);  
  28. }  

上面代码中的Gem对象是一个宝石类,完整代码如下

代码清单4

 

[javascript] view plaincopy
 
  1. function Gem(num){  
  2.     var self = this;  
  3.     base(self,LSprite,[]);  
  4.     self.num = num;  
  5.     self.bitmap = new LBitmap(new LBitmapData(datalist["gem0"+num]));  
  6.     self.bitmap.x=self.bitmap.y=10;  
  7.     self.addChild(self.bitmap);  
  8.       
  9. }  
  10. Gem.prototype.change = function (num){  
  11.     var self = this;  
  12.     self.num = num;  
  13.     self.bitmap.bitmapData = new LBitmapData(datalist["gem0"+num]);  
  14. }  

Gem类继承自LSprite,内部包含一个LBitmap对象来显示宝石图片。

代码清单3中调用了checkClear函数,来检验是否有可消除宝石,检测方法为先进行横向检索,然后进行纵向检索。

代码清单5

 

[javascript] view plaincopy
 
  1. clearList = [];  
  2.     //横向检索  
  3.     for(i=0;i<8;i++){  
  4.         checkList = [list[i][0]];  
  5.         for(j=1;j<8;j++){  
  6.             if(checkList[checkList.length - 1].num == list[i][j].num){  
  7.                 checkList.push(list[i][j]);  
  8.             }else{  
  9.                 clearList = addClearList(clearList,checkList);  
  10.                 checkList = [list[i][j]];  
  11.             }  
  12.         }  
  13.         clearList = addClearList(clearList,checkList);  
  14.     }  
  15.     //纵向检索  
  16.     for(i=0;i<8;i++){  
  17.         checkList = [list[0][i]];  
  18.         for(j=1;j<8;j++){  
  19.             if(checkList[checkList.length - 1].num == list[j][i].num){  
  20.                 checkList.push(list[j][i]);  
  21.             }else{  
  22.                 clearList = addClearList(clearList,checkList);  
  23.                 checkList = [list[j][i]];  
  24.             }  
  25.         }  
  26.         clearList = addClearList(clearList,checkList);  
  27.     }  

addClearList函数作用是将可消除宝石压入clearList数组,做法如下

 

代码清单6

 

[javascript] view plaincopy
 
  1. function addClearList(clearList,checkList){  
  2.     if(checkList.length >= 3){  
  3.         clearList = clearList.concat(checkList)  
  4.     }  
  5.     return clearList;  
  6. }  

游戏操作需要划动屏幕,但是在lufylegend.js引擎中,是没有划动屏幕的事件的,所以我通过下面MOUSE_DOWN,MOUSE_UP获取点击时和点击后的位置,来模拟一下划动事件。

 

代码清单7

 

[javascript] view plaincopy
 
  1. backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onDown);  
  2. backLayer.addEventListener(LMouseEvent.MOUSE_UP,onUp);  

再来看看具体做法,先是onDown函数。

代码清单8

 

[javascript] view plaincopy
 
  1. function onDown(e){  
  2.     if(mouse_down_obj.isMouseDown)return;  
  3.     continuous = 0;  
  4.     mouse_down_obj.x = e.offsetX;  
  5.     mouse_down_obj.y = e.offsetY;  
  6.     mouse_down_obj.time = new Date().getTime();  
  7.     mouse_down_obj.cx = e.offsetX/60 >>> 0;  
  8.     mouse_down_obj.cy = (e.offsetY - 120)/60 >>> 0;  
  9.     mouse_down_obj.isMouseDown = true;  
  10.     list[mouse_down_obj.cy][mouse_down_obj.cx].graphics.drawRect(1,"black",[0, 0, 60, 60],true,"#000000");  
  11. }  

通过e.offsetX和e.offsetY来获取点击位置,通过getTime()来获取点击时刻的时间。

在来看看onUp函数。

代码清单9

 

[javascript] view plaincopy
 
  1. function onUp(e){  
  2.     list[mouse_down_obj.cy][mouse_down_obj.cx].graphics.clear();  
  3.     if(new Date().getTime() - mouse_down_obj.time > 500){  
  4.         mouse_down_obj.isMouseDown = false;  
  5.         return;  
  6.     }  
  7.     var mx = e.offsetX - mouse_down_obj.x;  
  8.     var my = e.offsetY - mouse_down_obj.y;  
  9.     if(Math.abs(mx) > Math.abs(my)){  
  10.         if(mx > 50){  
  11.             move("right");  
  12.             return;  
  13.         }else if(mx < -50){  
  14.             move("left");  
  15.             return;  
  16.         }  
  17.     }else{  
  18.         if(my > 50){  
  19.             move("down");     
  20.             return;  
  21.         }else if(my < -50){  
  22.             move("up");  
  23.             return;  
  24.         }  
  25.     }  
  26.     mouse_down_obj.isMouseDown = false;  
  27. }  

函数中通过同样的方法得到点击结束时的位置和时间,然后与点击时刻做比较,最后计算划动的方向,然后根据划动的方向来调用move函数,让宝石移动。
move函数如下:

 

代码清单10

 

[javascript] view plaincopy
 
  1. function move(dir){  
  2.     direction = dir;  
  3.     var m = moveGem(dir,8);  
  4.     var mx = m[0],my = m[1];  
  5.     var obj,fun;  
  6.     for(var i=0;i<8;i++){  
  7.         if(mx == 0){  
  8.             obj = list[i][mouse_down_obj.cx];  
  9.         }else{  
  10.             obj = list[mouse_down_obj.cy][i];  
  11.         }  
  12.         if(i < 7){  
  13.             fun = null;  
  14.         }else{  
  15.             fun = function(){  
  16.                 hiddenObj.visible = true;  
  17.                 checkClear();  
  18.             };  
  19.         }  
  20.         LTweenLite.to(obj,0.3,  
  21.         {   
  22.             x:obj.x+mx,  
  23.             y:obj.y+my,  
  24.             onComplete:fun,  
  25.             ease:Strong.easeOut  
  26.         });  
  27.       
  28.     }  
  29. }  

下面以向右移动为例来说明一下move函数的处理过程,如下

 

先将最左边的一个宝石H移到最左边,然后再利用LTweenLite缓动类将整个一行8个宝石,向右缓动一个单位。向左的话正好相反,向上向下也是同样的原理。

每次缓动结束,要调用一次checkClear函数,来判断一下是否有可消除的宝石,如果有则开始消除宝石,如何来消除宝石呢?

我依然以向右划动来举例说明,看下面图片,假设D1,D2,D3可消除,E4,F4,G4可消除

 

那么首先将D1,D2,D3移到左边边界外,E4,F4,G4也移到边界外,表示被消除,之后对每一行的宝石进行位置判定,如每行的第一个宝石的x坐标应该是60,第二个为120,以此类推。如果他们不在自己的相应位置上,那么将其向左移动到规定位置就可以了,写成代码的话,如下。

代码清单11

 

[javascript] view plaincopy
 
  1. function moveList(){  
  2.     var gem,time,maxTime,mx,my,fun;  
  3.     maxTime = 0;  
  4.     switch(direction){  
  5.         case "left":  
  6.             for(i=0;i<8;i++){  
  7.                 for(j=0;j<8;j++){  
  8.                     gem = list[i][j];  
  9.                     mx = 60*j;  
  10.                     if(gem.x > mx){  
  11.                         time = 0.3*((gem.x-mx) / 60 >>> 0);  
  12.                         if(maxTime < time)maxTime = time;  
  13.                         fun = null;  
  14.                         if(gem.x > 420){  
  15.                             fun = function(gem){  
  16.                                 if(gem.x <= 420)gem.visible = true;  
  17.                             }  
  18.                         }  
  19.                         LTweenLite.to(gem,time,  
  20.                         {   
  21.                             x:mx,  
  22.                             onUpdate:fun,  
  23.                             onComplete:fun,  
  24.                             ease:Strong.easeOut  
  25.                         });  
  26.                     }  
  27.                 }  
  28.             }  
  29.             break;  
  30.         case "right":  
  31.             for(i=0;i<8;i++){  
  32.                 for(j=0;j<8;j++){  
  33.                     gem = list[i][j];  
  34.                     mx = 60*j;  
  35.                     if(gem.x < mx){  
  36.                         time = 0.3*((mx-gem.x) / 60 >>> 0);  
  37.                         if(maxTime < time)maxTime = time;  
  38.                         fun = null;  
  39.                         if(gem.x < 0){  
  40.                             fun = function(gem){  
  41.                                 if(gem.x >= 0)gem.visible = true;  
  42.                             }  
  43.                         }  
  44.                         LTweenLite.to(gem,time,  
  45.                         {   
  46.                             x:mx,  
  47.                             onUpdate:fun,  
  48.                             onComplete:fun,  
  49.                             ease:Strong.easeOut  
  50.                         });  
  51.                     }  
  52.                 }  
  53.             }  
  54.             break;  
  55.         case "up":  
  56.             for(i=0;i<8;i++){  
  57.                 for(j=0;j<8;j++){  
  58.                     gem = list[j][i];  
  59.                     my = 120+60*j;  
  60.                     if(gem.y > my){  
  61.                         time = 0.3*((gem.y-my) / 60 >>> 0);  
  62.                         if(maxTime < time)maxTime = time;  
  63.                         fun = null;  
  64.                         if(gem.y > 560){  
  65.                             fun = function(gem){  
  66.                                 if(gem.y <= 560)gem.visible = true;  
  67.                             }  
  68.                         }  
  69.                         LTweenLite.to(gem,time,  
  70.                         {   
  71.                             y:my,  
  72.                             onUpdate:fun,  
  73.                             onComplete:fun,  
  74.                             ease:Strong.easeOut  
  75.                         });  
  76.                     }  
  77.                 }  
  78.             }  
  79.             break;  
  80.         case "down":  
  81.             for(i=0;i<8;i++){  
  82.                 for(j=0;j<8;j++){  
  83.                     gem = list[j][i];  
  84.                     my = 120+60*j;  
  85.                     if(gem.y < my){  
  86.                         time = 0.3*((my-gem.y) / 60 >>> 0);  
  87.                         if(maxTime < time)maxTime = time;  
  88.                         fun = null;  
  89.                         if(gem.y < 120){  
  90.                             fun = function(gem){  
  91.                                 if(gem.y >= 120)gem.visible = true;  
  92.                             }  
  93.                         }  
  94.                         LTweenLite.to(gem,time,  
  95.                         {   
  96.                             y:my,  
  97.                             onUpdate:fun,  
  98.                             onComplete:fun,  
  99.                             ease:Strong.easeOut  
  100.                         });  
  101.                     }  
  102.                 }  
  103.             }  
  104.             break;  
  105.     }  
  106.     LTweenLite.to({},maxTime*1.5,  
  107.     {   
  108.         onComplete:checkStageClear,  
  109.         ease:Strong.easeOut  
  110.     });  
  111. }  

 

当然,游戏是有时间限制的,看下面的Clock类。

代码清单12

[javascript] view plaincopy
 
  1. function Clock(){  
  2.     var self = this;  
  3.     base(self,LSprite,[]);  
  4.     self.timer = 0;  
  5.     self.addTimer = 0.05;  
  6.     self.graphics.drawArc(5,"#333333",[0,0,70,0,2*Math.PI]);  
  7.       
  8. }  
  9. Clock.prototype.onframe = function (){  
  10.     var self = this;  
  11.     self.timer += self.addTimer;  
  12.     self.graphics.clear();  
  13.     self.graphics.drawArc(10,"#333333",[0,0,70,0,2*Math.PI]);  
  14.     self.graphics.drawArc(5,"#ffffff",[0,0,70,-Math.PI*0.5,Math.PI*self.timer/180-Math.PI*0.5]);  
  15. }  

首先将Clock加载到游戏中,然后再利用ENTER_FRAME时间轴事件,来不断调用Clock的onframe不断的绘制圆弧,当timer的数值大于等于360的时候代表画完了整个圆弧,那么游戏结束。

 

以上,游戏的主要原理都介绍完了,下面看看如何来把游戏转化为本地App

三,发布本地化App

首先,用Eclipse新建一个Android Project



注:如何搭建Android环境,我就不说了,网上教程多得是,随便百度一下吧。

然后,填写项目名称,并选择相应的sdk版本,这里我选了2.2

接着是填写相应数据,这个随自己心情就可以了。

接着,重点来了,在工程下的assets文件夹下,简历一个www文件夹(名字自己随意),然后把刚才开发好的游戏复制到这个文件夹下,当然,lufylegend引擎也必须复制过来。

接着修改res/layout/main.xml文件,添加webView,如下

 

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.     <WebView  
  7.         android:id="@+id/webView1"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent" />  
  10. </LinearLayout>  

最后,修改Main.java文件,利用webView来显示html网页,如下

 

 

[java] view plaincopy
 
  1. public class Main extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.         WebView webview = (WebView )findViewById(R.id.webView1);  
  8.         webview.getSettings().setJavaScriptEnabled(true);  
  9.         webview.setVerticalScrollbarOverlay(true);  
  10.         webview.loadUrl("file:///android_asset/www/index.html");  
  11.     }  
  12. }  

好了,运行程序吧。

 

画面如下:

最后,想要发布游戏为.apk文件的话,build一下就好了。

发布后的apk文件。

结束了,简单吧?

四,源码

最后给出本次游戏的源代码

http://lufylegend.com/lufylegend_download/GemGem.rar

注:只含游戏源码,lufylegend.js引擎请自己到官网下载 

For more complete information about compiler optimizations, see our Optimization Notice.