`
java2000.net
  • 浏览: 655940 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

一步一步教你开发《松鼠推箱子》手机游戏

阅读更多

这类游戏大家肯定都玩过,一个很有趣味性的小游戏。操作简单,具有一定的逻辑性。很适合无聊的时候消遣时间。:)

首先简单介绍下手机游戏的一般性开发过程。首先需要策划出一个游戏方案,也就是要给出一个游戏的整体形象。当然是想象中的。比如:游

戏题材,背景,操作方法,人物,与奖励机制。然后对这个策划方案进行可行性分析,包括技术,市场,可用资源等。下一步就是编码阶段,

一般编码和制作资源可以同步进行。 等程序和资源都弄好了,一个游戏的雏形就大致出来了。后面就是测试与移植等等工作。


我们要做的是让一只小松鼠推箱子,操作方法就是通过四方向键对松鼠进行上,下,左,右的移动。在移动过程中可以把碰到的箱子推到任意

一个方向。当然在游戏中需要设置一些障碍物,让游戏具备可玩性。游戏采用过关制,当松鼠把所有箱子推到指定的位置就算过关。所以每关

的场景要不同。这需要对每关的地图进行编排。好了,我们的游戏策划就算完成,嘿嘿!简单吧,想象是多么美好啊。


下面就没这么轻松了,我们要进行技术分析。就是具体的代码如何来实现的。首先我们来确定一下开发难点。对松鼠的操作很简单,就是四方

向移动,松鼠移动,箱子也移动,所以对按键处理也比较简单些。当箱子到达某个位置时,就会产生游戏过关事件。需要一个逻辑判断。那么

我们仔细想一下,这些所有的事件都发生在一张地图中。这张地图就包括了 箱子的初始化位置,箱子最终放置的位置,和障碍等。每一关地图

都要更换。这些位置也要变。所以我们发现每关的地图数据是最关键的。它决定了每关的不同场景和物体位置。好。那么我们就重点分析一下

地图。

我们把地图想象成一个网格,每个格子就是松鼠每次移动的步长,也是箱子移动的距离,这样问题就简化多了。首先我们设计一个8*8的数据结

构。按照这样的框架来思考。 每个格子都会有哪些属性呢?首先就是格子的坐标,包括X,Y两个数值,还有一些地图的属性,比如这个格子是

否为障碍,是否为初始化的箱子位置,是否为箱子终点的位置。由于我们的数据结构是二维的,但是还有一维表示不出来,所以我们设计一个

三维数据:如下:

private static int[][][] map_data = new int[8][8][5]; 
//第一维  -  [8] 表示地图的高,由8个格子组成
               
//第二维 -  [8] 表示地图的宽,由8个格子组成
                

//第三维  - [0] 每个格子的X坐标
               
//        - [1] 每个格子的Y坐标
               
//        - [2] 是否为障碍 0表示空地 1表示障碍
               
//        - [3] 箱子的终点坐标,0不是终点坐标 1绿箱子 2 红箱子
               
//        - [4] 箱子的初始化位置 [0]不是初始化坐标  [1]绿箱子 2红箱子

地图大致就是这样的数据结构,我们设计两种颜色的箱子,这样增加一下游戏的难度。


好了,有了地图,我们的逻辑就可以实现了。利用一点时间,我把游戏的图片画好了,好在我是美术专业毕业,画这些小像素图还挺顺利。

^+^.

我们先把游戏的界面部分处理一下。界面就是菜单,进度条,还有游戏中的绘制。 菜单和进度条略过,因为这些可以自己设计的。

下面是画地图和松鼠.箱子以及指示终点位置的方法。

//画地图
private void drawMap(Graphics g)
{
  

 for(int m = 0 ; m < map_data.length ; m ++ ) // Y坐标
 {
  for(int n = 0 ; n < map_data[m].length; n++) // X坐标
  {
    
    
   if(map_data[n][m][2] == 1) //如果是空地
   {
    g.drawImage(map[0],map_data[n][m][0],map_data[n][m][1],0);
      

   }else if(map_data[n][m][2] == 0) //如果是障碍
   {
    g.drawImage(map[1],map_data[n][m][0],map_data[n][m][1],0);     

 
      
   }

   
  }
   
 }

}

map数组是只有两个元素的图片数组,里面有两幅图,分别为空地和障碍。


//画松鼠
private void drawSqu(Graphics g)
{
 g.drawImage(squirrel[sdir],map_data[( splace[1] )][( splace[0] )][0],map_data[( splace[1] )][( splace[0] )][1],0);
}


这里的splace[] 是松鼠的初始化位置,这个随每关的不同,也会有变化。
sdir 表示松鼠的方向,对应着squirre[] 数组中的松鼠图片

//画箱子
private void drawBoxs(Graphics g)
{
 for(int i = 0; i < nplace.length; i++)
 {
  g.drawImage(nut[(nplace[i][2]-1)],map_data[(nplace[i][1])][(nplace[i][0])][0],map_data[(nplace[i][1])]

[(nplace[i][0])][1],0);
  
 }
}

nplace[][]  是箱子的初始化位置坐标,第一维表示有几个箱子,第二维表示 X,Y坐标 和 颜色 属性
nut[] 是箱子图片数组

//画箱子终点位置的指示
private void drawNutDest(Graphics g)
{
 for(int i = 0; i < ndplace.length; i++)
 {
  g.drawImage(nut[(ndplace[i][2]+1)],map_data[(ndplace[i][1])][(ndplace[i][0])][0],map_data[(ndplace[i][1])]

[(ndplace[i][0])][1],0);
 }
}

我们对箱子重点的指示也采用图片,这样使画面效果更美观一些。
同样 ndplace[][]  和 nplace[][]  的属性都一样。 只不过表示终点坐标
nut[]数组的另外元素表示 指示重点坐标的图片。

 

以上就是我们的游戏主界面。看着挺简单的吧。呵呵。下面要实现操作控制方法与判断输赢的逻辑了。嘿嘿,要有耐心。

前面我们提到,当移动松鼠时,箱子就跟着动,那么我们就分别写两个方法,来移动他们。

/*移动松鼠*/
private static final void moveSqu()

 

 /*表示在松鼠的移动方向是否有箱子*/
 boolean hit = false ;
  
 /*指示一个箱子可以被移动*/
 boolean mf = false ;
  
 /*当为向上移动时*/
 if( moveS[0] )
 { 
  
  /*当向上移动时,调整图片为第二张松鼠图*/
  sdir = 2 ;  
   
  /*将可移动表示设置为假*/
  moveS[0] = false;
   
   
  /*查找是否有箱子在松鼠傍边*/
  for(int r=0; r < nplace.length; r++) 
  {
   /*如果有箱子*/
   if( ((splace[1] - 1) == nplace[r][1]) && (splace[0]  == nplace[r][0] )){
     
    /*移动箱子,并返回一个判断,表示是否可以继续被移动*/
    mf = moveBoxs(0,r);
    
     
    /*设置碰撞标志*/
    hit = true ;
   }
    
  }
  
  /*如果傍边没箱子,是空地*/
  if(  (map_data[(splace[1] - 1)][(splace[0])][2] == 0 ) && (!hit ) ) 
  {  
    /*移动松鼠*/
    splace[1] -= 1 ;
     
  }
  /*如果碰到箱子*/
  if(hit)
  {
   /*并且这个箱子可以被推动*/
   if(mf){
    /*移动松鼠*/
    splace[1] -= 1 ;
    /*设置碰撞为否*/
    hit = false ;
   }
  }
   
 }
 /*向下方向*/
 if( moveS[1] )
 {
  //debug("down");
  sdir = 3;
  moveS[1] = false;
   
  for(int r=0; r < nplace.length; r++)
  {
   if( ((splace[1] + 1) == nplace[r][1] ) && ( splace[0]  == nplace[r][0] )){
    mf = moveBoxs(1,r);
    hit = true ;      
   }
    
  }
  if( (map_data[(splace[1] + 1)][(splace[0])][2] == 0 ) && (!hit))
  {
   splace[1] += 1 ; 
    
  }
  if(hit)
  {
   if(mf)
   {
    splace[1]+=1;
    hit = false ;
   }
  }
   
   
   
   
 }
 /*向左方向*/
 if( moveS[2] )
 {
  //debug("left");
  sdir = 0;
  moveS[2] = false;
   
  for(int r=0; r < nplace.length; r++)
  {
   if( ((splace[0] - 1) == nplace[r][0]) && ( splace[1] == nplace[r][1] )){
    mf = moveBoxs(2,r);
    hit = true ;      
   }    
    
  }
  if( (map_data[(splace[1])][(splace[0] - 1)][2] == 0 ) && (!hit)){
   splace[0] -= 1 ;
    
  }
  if(hit)
  {
   if(mf)
   {
    splace[0] -= 1 ;
    hit = false;
   }
  }
   
   
 }
 /*向右方向*/
 if( moveS[3] )
 {
  //debug("right");
  sdir = 1 ;
  moveS[3] = false;
  for(int r=0; r < nplace.length; r++)
  {
   if( ((splace[0] + 1) == nplace[r][0] ) && ( splace[1] == nplace[r][1] )){
    mf = moveBoxs(3,r);
    hit = true ;
   }
    
  }
  if( (map_data[(splace[1])][(splace[0] + 1)][2] == 0) && (!hit)) {
   splace[0] += 1 ;
    
  }
  if(hit)
  {
   if(mf)
   {
    splace[0] += 1 ;
    hit = false ;
   }
  }
  
   
 }

  

}

上面这个方法看起来比较长,其实逻辑比较简单,就是分别对应四个方向的移动来判断。可以看向上方向移动的注释。moveS[]是个blooean数

组,用来表示松鼠的移动方向,这个数组会在keyPressed()被赋值,当某方向键按下时对应方向的标志就设置为真。下面的moveBoxs() 方法,是

判断某个箱子在被推动的方向上是否还有其它箱子阻碍,如果有就返回true.否则false.并且移动这个箱子。

 

/*
*
*方法功能:移动箱子
*
*参数: dir:被推动的方向 . nm: 表示哪个箱子
*
*返回值: 该箱子是否可以被推动
*/
private static final boolean moveNuts(int dir,int nm)
{
 /*指示另外的箱子在该箱子傍边*/
 boolean hit = false;
  
 /*临时变量*/
 boolean mf = false ;
 
 switch(dir)
 {
  case 0: //'up'

   /*对所有箱子坐标遍历*/
   for(int i = 0 ; i < nplace.length ; i++)
   {
    /*使用坐标判断,如果当前箱子要移动的方向上有其他箱子那么就标志上*/
    if( ((nplace[nm][1] - 1) == nplace[i][1] ) && ( nplace[nm][0] == nplace[i][0]))
     hit = true ;

   }
   /*如果为空地*/
   if( (map_data[(nplace[nm][1] - 1)][(nplace[nm][0])][2] == 0 ) && (!hit) )
   {
    /*移动这个箱子,并且将返回值设置为可以移动*/
    nplace[nm][1] -= 1 ;
    mf = true ;
   }
     
  break;
  case 1: //'down'
   for(int i = 0 ; i < nplace.length ; i++)
   {
    if( ((nplace[nm][1] + 1) == nplace[i][1] ) && ( nplace[nm][0] == nplace[i][0]))
     hit = true ;

   }
   if( (map_data[(nplace[nm][1] + 1)][(nplace[nm][0])][2] == 0) && (!hit) )
   {
    nplace[nm][1] += 1 ;      
    mf = true ;
   }
  break;
  case 2: //'left'
   for(int i = 0 ; i < nplace.length ; i++)
   {
    if( ((nplace[nm][1]) == nplace[i][1] ) && ( (nplace[nm][0] - 1) == nplace[i][0]))
     hit = true ;
   }
   if( (map_data[(nplace[nm][1])][(nplace[nm][0] - 1)][2] == 0) && (!hit))
   {
     nplace[nm][0] -= 1 ;
     mf = true ;
   }
  break;
  case 3: //'right'
   for(int i = 0 ; i < nplace.length ; i++)
   {
    if( ((nplace[nm][1]) == nplace[i][1] ) && ( (nplace[nm][0] + 1) == nplace[i][0]))
     hit = true ;

   }
     
   if( (map_data[(nplace[nm][1])][(nplace[nm][0] + 1)][2] == 0) && (!hit) )
   {
    nplace[nm][0] += 1 ;      
    mf = true ;
   }
  break;
 }

 return mf ;
}


这个方法跟判断松鼠是否可以移动原理一样,其实完全可以和移动松鼠的方法结合一起来处理,而且可以优化很多东西,但为了逻辑更清晰,

就分开来做。


/*判断过关*/
private static final boolean isWin()
{
 boolean temp = false;
 int nn = 0;
 for(int r = 0 ; r < nplace.length ; r++)
 {
  for(int m = 0 ; m < ndplace.length ; m++)
  {
   if( (nplace[r][0] == ndplace[m][0] ) && (nplace[r][1] == ndplace[m][1]))
    nn++;
  }
 }

 if(nn == nplace.length)
  temp = true;
 else
  temp = false;

 return temp;
}

判断过关的逻辑很简单,就是对目的地坐标与当前箱子坐标一一对照,如果所有箱子都已经被正确推到目的地,就算过关。


到现在,我们的游戏界面,和游戏逻辑实现就都完成了,感觉是不是很简单。呵呵,当然要完成整个游戏,还要写一些固定的方法。比如

keyPressed();获得按键值  paint() 来画图  线程run() 来实现刷屏幕等等。由于篇幅有限就不一一介绍了。下面附上一幅游戏完成的截图。

看看效果吧。

代码与图片下载:moveBox.rar 

《松鼠推箱子》游戏截图

程序设计与图片制作:关文柏       Email:k7sem_88@hotmail.com

 

 

分享到:
评论

相关推荐

    基于JAVA的推箱子游戏(源码+lun文+视频).rar

    基于JAVA的推箱子游戏系统主要用于实现游戏推箱子功能,提供多种不同难度的关卡。本系统结构如下: (1)初始化模块: 该模块包括屏幕初始化和游戏第一关的初始化。屏幕初始化用于输出欢迎信息和操 (2)画图模块: 该...

    人教五年级松鼠PPT学习教案.pptx

    《人教五年级松鼠PPT学习教案》便是这样的一个优秀示例,它通过结合自然科学和语文学科,将松鼠这一自然界中的生物作为教学载体,引导学生进行综合性的学习与探究。 首先,教案以松鼠的生物学分类作为引入,让学生...

    易语言Squirrel松鼠脚本支持库

    Squirrel(松鼠)是一种较新的脚本语言,它从著名的LUA语言继承了很多特性,适用的范围也与LUA语言相似。esquirrel3.fne 支持库。esquirrel3_static.lib 静态库。Squirrel 3.1 标准库 .docx 松鼠脚本标准库文档(机...

    libgdx 小游戏 小松鼠过马路 源码 亲测可以使用

    这个压缩包提供的"小松鼠过马路"源码是一个基于LibGDX框架的示例游戏,通过分析这个项目,我们可以深入理解LibGDX在游戏开发中的应用。 首先,LibGDX的核心组件包括Stage、SpriteBatch、Texture、TextureRegion等。...

    人教小学语文五年级上册松鼠PPT学习教案.pptx

    这篇PPT学习教案主要针对人教版小学语文五年级上册的一篇关于松鼠的文章进行讲解,旨在帮助学生深入理解松鼠的特点和习性。以下是根据PPT内容提炼出的相关知识点: 1. **松鼠的外形特征**: - 松鼠的面容是“清秀...

    Bubble Shooter 松鼠泡泡射手Unity游戏项目源码C#

    Bubble Shooter 松鼠泡泡射手Unity游戏项目源码C# 支持Unity版本2020.1.14f1及以上 商品描述 怎么玩? • 在屏幕上滑动手指,将球射向气球并粘在最近的球上。 • 当您看到3 个相同颜色的球在一起时,您可以添加更多...

    【《松鼠》阅读题与答案】松鼠和狼阅读答案.docx

    "松鼠阅读题与答案" 松鼠是一种美丽的小动物,乖巧,驯良,很讨人喜爱。它们面容清秀,眼睛闪闪发光,身体强健,四肢轻快,特别灵敏,特别机警。松鼠的身体结构非常适合树栖生活,它们可以轻松地在树枝间跳跃,钻入...

    松鼠短视频完美开源系统源码 后台+APP双端源码

    开发语言:Uni-app混合开发 源码包括:源码包括;安卓App+苹果App +手机端+后台服务端 主要功能:主要包含“首页”、“收藏”、“频道”、“我的”、“视频”、“设置”等功能,实现用户对APP端界面管理及使用各项...

    松鼠HTML编辑器 V1.5.2718

    3. **模板与库**:为了加快开发速度,编辑器可能会内置各种网页模板和组件库,如按钮、表单、图片滑块等,只需一键插入即可。 4. **响应式设计**:考虑到现代网页需要适应不同设备的屏幕尺寸,松鼠HTML编辑器可能...

    UC松鼠大战分析

    爱玩手机松鼠大战可以来看看,可能对你有帮助哦

    【《小松鼠看错了》阅读答案】小松鼠阅读答案.docx

    故事中,达尔文在树林里散步时,因为专注观察小鸟而引来了一只小松鼠,小松鼠误以为他是木桩,爬到了他的肩上。松鼠妈妈的担忧并未成真,因为达尔文是个爱护动物的人。 1. 对于题目中的词汇解释: - 得意 (b):...

    松鼠压缩(联想版)残留彻底删除工具

    装有联想管家的电脑,在打开压缩包时可能会被联想应用商店推装松鼠压缩。 这个松鼠压缩软件卸载后,还有很多注册表残留,导致压缩文件打开方式里有松鼠压缩去不掉。 用本工具可以一键清理松鼠压缩(联想版)的打开方式...

    三只松鼠公司案例分析.docx

    三只松鼠公司案例分析 一、公司概况 公司概况是指对企业的基本情况的了解,包括企业的名称、成立时间、注册资本、法人代表、注册地址、经营范围等信息。在本案例中,安徽三只松鼠电子商务有限公司的公司概况是非常...

    【小松鼠阅读答案】小松鼠原文阅读答案.docx

    在深入探讨关于小松鼠的原文及阅读答案之前,让我们首先对这篇文章进行概览。它讲述了一只野生小松鼠在被作者收留后,从野性十足到逐步与人类建立情感联系,并最终回归自然的故事。本文作者通过小松鼠的视角展现了...

    Android-全网视频嗅探缓存APP-治疗你的松鼠症[比心]

    全网视频嗅探缓存APP-治疗你的松鼠症[比心]

    三只松鼠的STP策略.pdf

    三只松鼠的STP策略.pdf

    五年级语文上册 第五单元 17《松鼠》说课稿 新人教版-新人教版小学五年级上册语文教案.doc

    【五年级语文上册 第五单元 17《松鼠》说课稿】是一份针对新人教版小学五年级上册语文课程的教案,旨在通过学习《松鼠》这篇科学小品文,使学生了解说明文的特点,特别是科学小品文如何通过文学手法介绍动物。...

    三只松鼠波特五力分析.doc

    三只松鼠波特五力分析.doc

    人教小学一年级语文松鼠与松果PPT教案.pptx

    人教小学一年级语文松鼠与松果PPT教案.pptx

Global site tag (gtag.js) - Google Analytics