[html5游戏开发]经典的推箱子

这一次先来看一个经典的推箱子游戏,相信大家也都知道这款游戏,推箱子游戏最早源于日本,是一款极其锻炼逻辑思考能力的游戏,箱子只能推不能拉,玩家必须在一个有限的空间里,将所有的箱子归位,如下图所示。

[html5游戏开发]经典的推箱子_第1张图片

 

这是我用最新版lufylegend.js引擎开发的,想挑战一下的朋友,可以点击下面的游戏链接试一下自己能通过几关。

http://lufylegend.com/demo/box

游戏一共6关,我在游戏里加入了排名系统,每过一关可以上传自己的成绩,跟大家比拼一下,或者您也可以将自己的过关方法心得等回复到文章下面。

 制作开始

好了,废话说完了,现在来看看如何来制作这款游戏。

一,首先,你需要下载lufylegend.js引擎

下面是我在博客的lufylegend-1.6.0发布帖

http://blog.csdn.net/lufy_legend/article/details/8593968

 

下面一步步来进入开发正题。

二,绘制背景和箱子

我们先来准备一张图,

如果我们将上面的图平均分割成5份,那么他们的序号分别为0,1,2,3,4

我们利用上面5个小图片就可以拼接任意的房间以及房间内箱子的摆放。

比如,我博客一开始的示例图1,它是游戏第一关的截图,要绘制这个房间,首先要知道这些图片应该摆放的位置,我们预先准备一个数组。

[javascript] view plaincopy

1.  var stage01 = [  

2.  [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],  

3.  [-1,-1, 1, 1, 1, 1, 1, 1,-1,-1,-1],  

4.  [-1,-1, 1, 0, 0, 0, 0, 1, 1,-1,-1],  

5.  [-1,-1, 1, 0, 0, 4, 0, 0, 1,-1,-1],  

6.  [-1,-1, 1, 4, 4, 0, 4, 4, 1,-1,-1],  

7.  [-1,-1, 1, 0, 0, 4, 0, 0, 1,-1,-1],  

8.  [-1,-1, 1, 1, 0, 0, 0, 0, 1,-1,-1],  

9.  [-1,-1,-1, 1, 1, 1, 1, 1, 1,-1,-1],  

10. [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]  

11. ];  

上面的-1表示不摆放,然后0,1,4等分别对应着图2中的序号。

按照这个数组来绘制房间就简单了,看下面的函数

[javascript] view plaincopy

1.  function drawFloor(x,y){  

2.      if(list[y][x] < 0)return;  

3.      var bitmap = new LBitmap(bitmapDataList[list[y][x]]);  

4.      bitmap.x = x*STEP;  

5.      bitmap.y = y*STEP;  

6.      boxLayer.addChild(bitmap);  

7.  }  

这个list数组就是上面的stage01数组,参数x,y分别是数组的列和行的序号,STEP是每个小图片的长度,绘制一个小图块,其实我就是建立了一个LBitmap对象。

关于LSpriteLBitmap等对象是lufylegend.js引擎中很常用的对象,关于它们的用法,请大家参照官方的API文档,或者看我以前的一些文章来了解一下,这里不加赘述了。

当然,一开始,房间里要有箱子,箱子一开始的位置也是需要预先设置好的,我们同样建立一个数组。

[javascript] view plaincopy

1.  var box01 = [  

2.  {x:3,y:3},  

3.  {x:4,y:3},  

4.  {x:5,y:3},  

5.  {x:5,y:5},  

6.  {x:6,y:5},  

7.  {x:7,y:5}  

8.  ];  

绘制箱子的函数如下

[javascript] view plaincopy

1.  function drawBox(){  

2.      var bitmap;  

3.      for(var i=0;i

4.          bitmap = new LBitmap(bitmapDataList[2]);  

5.          bitmap.x = boxList[stageIndex][i].x*STEP;  

6.          bitmap.y = boxList[stageIndex][i].y*STEP;  

7.          boxLayer.addChild(bitmap);  

8.          nowBoxList.push(bitmap);  

9.      }  

10. }  

上面,我同样利用LBitmap对象来显示这些箱子,nowBoxList数组用来储存这些已经加载到游戏界面上的箱子对象,之后用来判断游戏过关。

因为stage01数组中的4就表示箱子需要还原的位置,所以在判断游戏是否过关的时候,只需要判断下这些位置是否与所有箱子的位置重合,判断方法如下。

[javascript] view plaincopy

1.  function checkBox(){  

2.      var bitmap,x,y,win=true;  

3.      list = [];  

4.      for(var i=0;i

5.          list.push(stageList[stageIndex][i].join(",").split(","));  

6.      }  

7.        

8.      for(var i=0;i

9.          bitmap = nowBoxList[i];  

10.         x = bitmap.x / STEP;  

11.         y = bitmap.y / STEP;  

12.         if(list[y][x] == 4){  

13.             bitmap.bitmapData = bitmapDataList[3];  

14.         }else{  

15.             bitmap.bitmapData = bitmapDataList[2];  

16.             win = false;  

17.         }  

18.         list[y][x] += 10;  

19.     }  

20.     if(win)gameClearShow();  

21. }  

代码我是直接从程序中截取的,所以出现了些新的数组和对象。

stageList储存了所有的关卡信息,stageIndex是当前关卡的序号,stageList[stageIndex]就可以获取当前关卡的信息,bitmapDataList数组储存了图1中小图片的LBitmapData对象,这些暂且不说,关键是下面。

[javascript] view plaincopy

1.  if(list[y][x] == 4){  

2.      bitmap.bitmapData = bitmapDataList[3];  

3.  }else{  

4.      bitmap.bitmapData = bitmapDataList[2];  

5.      win = false;  

6.  }  

函数中循环了所有箱子的位置,如果他们的位置的序号为4,则表示该箱子已经归位,全部归位表示过关,否则游戏继续,返回false

三,主人公登场,推动箱子。

同样准备一张图片,如下

[html5游戏开发]经典的推箱子_第2张图片

人物走动动画,当然就需要lufylegend引擎中另一个重要的对象LAnimation,它专门用来顺序播放图片以形成动画,具体用法请参照官方API文档。

下面是主人公的构造器

[javascript] view plaincopy

1.  /** 

2.   * 循环事件  

3.   * @param data 图片数据 

4.   * @param row 图片分割行数 

5.   * @param col 图片分割列数 

6.   **/  

7.  function Character(data,row,col){  

8.      base(this,LSprite,[]);  

9.      var self = this;  

10.     //设定人物动作速度  

11.     self.speed = 2;  

12.     self.speedIndex = 0;  

13.     //设定人物大小  

14.     data.setProperties(0,0,data.image.width/col,data.image.height/row);  

15.     //得到人物图片拆分数组  

16.     var list = LGlobal.divideCoordinate(data.image.width,data.image.height,row,col);  

17.     //设定人物动画  

18.     self.anime = new LAnimation(this,data,list);  

19.     //设定不移动  

20.     self.move = false;  

21.     //在一个移动步长中的移动次数设定  

22.     self.moveIndex = 0;  

23. };  

主人公如何推动箱子,看下面的onmove函数

[javascript] view plaincopy

1.  /** 

2.   * 开始移动  

3.   **/  

4.  Character.prototype.onmove = function (){  

5.      var self = this;  

6.      //设定一个移动步长中的移动次数  

7.      var ml_cnt = 4;  

8.      //计算一次移动的长度  

9.      var ml = STEP/ml_cnt;  

10.     //根据移动方向,开始移动  

11.     switch (self.direction){  

12.         case UP:  

13.             self.y -= ml;  

14.             if(box)box.y -= ml;  

15.             break;  

16.         case LEFT:  

17.             self.x -= ml;  

18.             if(box)box.x -= ml;  

19.             break;  

20.         case RIGHT:  

21.             self.x += ml;  

22.             if(box)box.x += ml;  

23.             break;  

24.         case DOWN:  

25.             self.y += ml;  

26.             if(box)box.y += ml;  

27.             break;  

28.     }  

29.     self.moveIndex++;  

30.     //当移动次数等于设定的次数,开始判断是否继续移动  

31.     if(self.moveIndex >= ml_cnt){  

32.         self.moveIndex = 0;  

33.         box = null;  

34.         self.move = false;  

35.         checkBox();  

36.     }  

37. };  

可以看到,箱子是不是跟着主人公一起走,关键是要看box这个变量,这个变量的值是在下面的checkRoad函数中设置的。

[javascript] view plaincopy

1.  Character.prototype.checkRoad = function (dir){  

2.      var self = this;  

3.      var tox,toy;  

4.      //开始计算移动目的地的坐标  

5.      switch (dir){  

6.          case UP:  

7.              tox = 0;  

8.              toy = -1;  

9.              break;  

10.         case LEFT:  

11.             tox = -1;  

12.             toy = 0;  

13.             break;  

14.         case RIGHT:  

15.             tox = 1;  

16.             toy = 0;  

17.             break;  

18.         case DOWN:  

19.             tox = 0;  

20.             toy = 1;  

21.             break;  

22.     }  

23.     if(list[self.y/STEP + toy][self.x/STEP + tox]==1)return false;  

24.     if(list[self.y/STEP + toy][self.x/STEP + tox]>4){  

25.         if(list[self.y/STEP + toy*2][self.x/STEP + tox*2]==1 || list[self.y/STEP + toy*2][self.x/STEP + tox*2]>4)return false;  

26.         box = getBox(self.x + tox*STEP,self.y + toy*STEP);  

27.     }  

28.     return true;  

29. };  

其实,就是判断一下主人公要走的方向的前方是不是有障碍物,如果障碍物是墙则不可移动,如果是箱子的话,就要看看箱子的后面是不是有障碍物,如果有则不可移动,否则箱子就需要跟着主人公一起移动,将box设置为主人公前方的箱子即可。
上面这个函数,是在人物即将发生移动的时候被调用的,如下。

[javascript] view plaincopy

1.  /** 

2.   * 改变人物方向,并判断是否可移动 

3.   **/  

4.  Character.prototype.changeDir = function (dir){  

5.      var self = this;  

6.      if(self.move)return;  

7.      self.direction = dir;  

8.      self.anime.setAction(dir);  

9.      if(!self.checkRoad(dir))return;  

10.     self.move = true;  

11.     steps.text = parseInt(steps.text) + 1;  

12. };  

当图1中的方向图标被按下的时候,根据点击的方向,来实现人物的移动。

点击方向图标的方法当然是鼠标事件

[javascript] view plaincopy

1.  ctrlLayer.addEventListener(LMouseEvent.MOUSE_UP,onCtrl);  

然后在onCtrl函数中根据点击的位置,来进行相应的移动。

[javascript] view plaincopy

1.  function onCtrl(event){  

2.      var ctrlSize = 60;  

3.      if(event.selfX >= ctrlSize && event.selfX <= ctrlSize*2){  

4.          if(event.selfY >= 0 && event.selfY <= ctrlSize){  

5.              player.changeDir(UP);  

6.          }else if(event.selfY >= ctrlSize*2 && event.selfY <= ctrlSize*3){  

7.              player.changeDir(DOWN);  

8.          }  

9.      }else if(event.selfY >= ctrlSize && event.selfY <= ctrlSize*2){  

10.         if(event.selfX >= 0 && event.selfX <= ctrlSize){  

11.             player.changeDir(LEFT);  

12.         }else if(event.selfX >= ctrlSize*2 && event.selfX <= ctrlSize*3){  

13.             player.changeDir(RIGHT);  

14.         }  

15.     }  

16. }  

这样,游戏的主要功能部分,就介绍完了。

四,建一个开始画面


使用lufylegend.js引擎做个界面,可以说毫无难度,代码如下。

[javascript] view plaincopy

1.  function GameLogo(){  

2.      base(this,LSprite,[]);  

3.      var self = this;  

4.        

5.      var logolist = [[1,1,1,1],[1,2,4,1],[1,4,2,1],[1,1,1,1]];  

6.      var bitmap,logoLayer;  

7.        

8.      logoLayer = new LSprite();  

9.      logoLayer.graphics.drawRect(6,"#FF7F50",[0,0,LGlobal.width,LGlobal.height],true,"#FFDAB9");  

10.     self.addChild(logoLayer);  

11.       

12.     logoLayer = new LSprite();  

13.     logoLayer.x = 50;  

14.     logoLayer.y = 50;  

15.     for(var i=0;i

16.         for(var j=0;j

17.             bitmap = new LBitmap(bitmapDataList[logolist[i][j]]);  

18.             bitmap.x = j*STEP;  

19.             bitmap.y = i*STEP;  

20.             logoLayer.addChild(bitmap);  

21.         }  

22.     }  

23.     bitmap = new LBitmap(new LBitmapData(imglist["player"],0,0,STEP,STEP));  

24.     bitmap.x = STEP;  

25.     bitmap.y = 2*STEP;  

26.     logoLayer.addChild(bitmap);  

27.     self.addChild(logoLayer);  

28.       

29.     labelText = new LTextField();  

30.     labelText.rotate = -20;  

31.     labelText.color = "#4B0082";  

32.     labelText.font = "HG行書体";  

33.     labelText.size = 100;  

34.     labelText.x = 300;  

35.     labelText.y = 50;  

36.     labelText.stroke = true;  

37.     labelText.lineWidth = 4;  

38.     labelText.text = "";  

39.     self.addChild(labelText);  

40.       

41.     labelText = new LTextField();  

42.     labelText.color = "#4B0082";  

43.     labelText.font = "HG行書体";  

44.     labelText.size = 100;  

45.     labelText.x = 450;  

46.     labelText.y = 60;  

47.     labelText.stroke = true;  

48.     labelText.lineWidth = 4;  

49.     labelText.text = "";  

50.     self.addChild(labelText);  

51.       

52.     labelText = new LTextField();  

53.     labelText.rotate = 20;  

54.     labelText.color = "#4B0082";  

55.     labelText.font = "HG行書体";  

56.     labelText.size = 100;  

57.     labelText.x = 600;  

58.     labelText.y = 60;  

59.     labelText.stroke = true;  

60.     labelText.lineWidth = 4;  

61.     labelText.text = "";  

62.     self.addChild(labelText);  

63.       

64.     labelText = new LTextField();  

65.     labelText.color = "#B22222";  

66.     labelText.font = "HG行書体";  

67.     labelText.size = 40;  

68.     labelText.x = 100;  

69.     labelText.y = 250;  

70.     labelText.stroke = true;  

71.     labelText.lineWidth = 4;  

72.     labelText.text = "Click to Start Game !!";  

73.     self.addChild(labelText);  

74.       

75.     var social = new Social();  

76.     social.x = 220;  

77.     social.y = 330;  

78.     self.addChild(social);  

79.       

80.     labelText = new LTextField();  

81.     labelText.font = "HG行書体";  

82.     labelText.size = 14;  

83.     labelText.x = 400;  

84.     labelText.y = 390;  

85.     labelText.text = "- Html5 Game Engine lufylegend.js";  

86.     self.addChild(labelText);  

87.     labelText = new LTextField();  

88.     labelText.color = "#006400";  

89.     labelText.font = "HG行書体";  

90.     labelText.size = 14;  

91.     labelText.x = 400;  

92.     labelText.y = 410;  

93.     labelText.text = "http://www.lufylegend.com/lufylegend";  

94.     self.addChild(labelText);  

95.       

96.     self.addEventListener(LMouseEvent.MOUSE_UP,menuShow);  

97. };  

就是显示几张图片,以及添加一些文字,LTextField对象的使用方法请参考官方API文档。

五,建一个选择画面

如下。

5

代码如下。

[javascript] view plaincopy

1.  function GameMenu(){  

2.      base(this,LSprite,[]);  

3.      var self = this;  

4.        

5.      var menuLayer;  

6.      menuLayer = new LSprite();  

7.      menuLayer.graphics.drawRect(6,"#ADD8E6",[0,0,LGlobal.width,LGlobal.height],true,"#E6E6FA");  

8.      self.addChild(menuLayer);  

9.        

10.     labelText = new LTextField();  

11.     labelText.color = "#B22222";  

12.     labelText.font = "HG行書体";  

13.     labelText.size = 40;  

14.     labelText.x = 200;  

15.     labelText.y = 30;  

16.     labelText.stroke = true;  

17.     labelText.lineWidth = 4;  

18.     labelText.text = "Please select !!";  

19.     menuLayer.addChild(labelText);  

20.     for(var i=0;i

21.         self.stageVsMenu(stageMenu[i]);  

22.     }  

23. };  

24. GameMenu.prototype.stageVsMenu = function(obj){  

25.     var self = this;  

26.       

27.     var menuButton,btn_up;  

28.     if(obj.open){  

29.         btn_up = new LSprite();  

30.         btn_up.graphics.drawRect(2,"#000",[0,0,150,90],true,"#191970");  

31.         labelText = new LTextField();  

32.         labelText.color = "#ffffff";  

33.         labelText.font = "HG行書体";  

34.         labelText.size = 20;  

35.         labelText.x = 40;  

36.         labelText.y = 5;  

37.         btn_up.addChild(labelText)  

38.         labelText.text = ""+(obj.index+1)+"";  

39.           

40.         labelText = new LTextField();  

41.         labelText.color = "#ffffff";  

42.         labelText.font = "HG行書体";  

43.         labelText.size = 12;  

44.         labelText.x = 10;  

45.         labelText.y = 40;  

46.         btn_up.addChild(labelText)  

47.         labelText.text = "step:"+obj.step;  

48.         labelText = new LTextField();  

49.         labelText.color = "#ffffff";  

50.         labelText.font = "HG行書体";  

51.         labelText.size = 12;  

52.         labelText.x = 10;  

53.         labelText.y = 60;  

54.         btn_up.addChild(labelText)  

55.         labelText.text = "times:"+obj.times;  

56.           

57.           

58.         var btn_down = new LSprite();  

59.         btn_down.graphics.drawRect(2,"#000",[0,0,150,90],true,"#2F4F4F");  

60.         labelText = new LTextField();  

61.         labelText.color = "#ffffff";  

62.         labelText.font = "HG行書体";  

63.         labelText.size = 20;  

64.         labelText.x = 40;  

65.         labelText.y = 5;  

66.         labelText.text = ""+(obj.index+1)+"";  

67.         btn_down.addChild(labelText);  

68.           

69.         labelText = new LTextField();  

70.         labelText.color = "#ffffff";  

71.         labelText.font = "HG行書体";  

72.         labelText.size = 12;  

73.         labelText.x = 10;  

74.         labelText.y = 40;  

75.         btn_down.addChild(labelText)  

76.         labelText.text = "step:"+obj.step;  

77.         labelText = new LTextField();  

78.         labelText.color = "#ffffff";  

79.         labelText.font = "HG行書体";  

80.         labelText.size = 12;  

81.         labelText.x = 10;  

82.         labelText.y = 60;  

83.         btn_down.addChild(labelText)  

84.         labelText.text = "times:"+obj.times;  

85.           

86.         menuButton = new LButton(btn_up,btn_down);  

87.         menuButton.obj = obj;  

88.         menuButton.addEventListener(LMouseEvent.MOUSE_UP,function(event,self){  

89.             gameStart(self.obj.index);  

90.         });  

91.     }else{  

92.         btn_up = new LSprite();  

93.         btn_up.graphics.drawRect(2,"#000",[0,0,150,90],true,"#708090");  

94.         labelText = new LTextField();  

95.         labelText.color = "#ffffff";  

96.         labelText.font = "HG行書体";  

97.         labelText.size = 20;  

98.         labelText.x = 40;  

99.         labelText.y = 5;  

100.         btn_up.addChild(labelText)  

101.         labelText.text = "???";  

102.         menuButton = btn_up;  

103.     };  

104.     self.addChild(menuButton);  

105.     menuButton.x = obj.x * 220 + 100;   

106.     menuButton.y = obj.y * 140 + 130;  

107. }  



好了,游戏主要的代码已经都贴出来了。

 

你可能感兴趣的:([html5游戏开发]经典的推箱子)