游戏介绍:

对对碰游戏在n*n的游戏池中进行,每个格子中有一个图案。鼠标连续选中两个横排或竖排相邻的图案,它们的位置会互换,互换后如果横排或者竖排有3个以上相同的图像,则可以消去该图像,并得分。

游戏的基本规则如下:

①交换

玩家选择两个横排或竖排相邻的图案进行位置互换,如果互换成功则能消去图案,否则取消位置交换。

②消去

玩家选择两个横排或竖排相邻的图案进行位置互换,互换后如果横排或者竖排上有超过3个相同的图像,则消去这几个相同的图像,消去图像后的空格由其上面的图案掉下来补齐,每次消去图像,玩家都可以获得分数。

③连锁

玩家消去图像后,上面的图像掉下来补齐,如果此时游戏池里有连续相同的3个或3个以上的图像,则可以消去这些图像。消去后的空格由上面的图像掉下来补充,继续触发连锁,直到不满足连锁条件为止。

本次制作的对对碰运行效果如下图所示:

使用到的素材文件夹:

素材及完整源码链接:https://pan.baidu.com/s/1J1iXvgvVrNZI_Waq3v3xNA 提取码: iefw

游戏设计的思路:

游戏面板是n*n的方块组成,在完成其游戏功能的前提下,需要尽可能保持其扩展性。在这里我设置图案的种类共有n-2种,假如10*10的面板,则有8种图案,假如是8*8的面板,则有6种图案。游戏池数据使用二维数组map保存,存储的是图案种类ID,使用Image数组pics存储各种图案的图像,绘画面板时通过数组信息和图片ID即可对游戏池状况进行绘画。在定时器progress的控制下,推动游戏进行,这里设置游戏时间是100秒。使用isClick变量去标记玩家是不是第二次点击图案,使用clickX、clickY变量记录第一次点击图案的数组下标。

获取图片及显示图片:
使用Toolkit工具类获取图片,存储到Image数组,再遍历map数组,根据数组下标转换成左上角像素坐标,比如说map[3][4],在这里它的左上角x坐标为4*W+leftX,y坐标为3*W+leftY。最后根据左上角坐标和图案ID,绘制边长为W的图案。

private void getPics() {for(int i=0;i<n-1;i++){pics[i] = Toolkit.getDefaultToolkit().getImage("D://Game//SupperzzleGame//pic"+i+".png");}}public void paint(Graphics g){g.clearRect(0, 0, 700, 600);for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(map[i][j]!=EMPTY){g.drawImage(pics[map[i][j]],leftX+W*j,leftY+W*i,W,W,this);}else{g.clearRect(leftX+W*j,leftY+W*i,W, W);}}}}

玩家鼠标点击事件:

先获取鼠标点击处减去偏移量后的x,y坐标,如果不在游戏池面板内,return;

用tempX存储这次点击的二维数组x下标,tempY存储这次点击的二维数组y下标(形如map[x][y])。

①如果是第一次点击:

修改isClick标记变量为true,用clickX,clickY记录此次点击的数组x下标和y下标。

②如果是第二次点击:

判断两次点击的图案是否横排或竖排相邻,如果相邻则先交换两数组元素的值。

使用isThreeLinked方法判断两个图案交换后是否存在可消去图案的情况,如果存在,则消去可消去的图案并使用downAnimal方法补齐游戏池,接着扫描游戏池中是否存在可消除的图案,如果存在则触发连锁消去事件,接着使用downAnimal方法补齐游戏池....直到当前游戏池没有可消去的图案为止。

如果交换后不存在可消去图案的情况,两次点击的图案位置重新换回。

public void mousePressed(MouseEvent e) {int x = e.getX()-leftX;int y = e.getY()-leftY;if(x<0||y<0||x>=50*n||y>=50*n){return ;}int tempX = y/W;int tempY = x/W;if(isClick){//第二次点击if((tempX==clickX&&(tempY==clickY+1||tempY==clickY-1))||(tempY==clickY&&(tempX==clickX+1||tempX==clickX-1))){//如果两次点击的图案相邻//交换int help = map[tempX][tempY];map[tempX][tempY] = map[clickX][clickY];map[clickX][clickY] = help;repaint();if(isThreeLinked(tempX,tempY)||isThreeLinked(clickX,clickY)){//判断是否存在可消去的方块//    System.out.println("可以消去");if(isThreeLinked(tempX,tempY)){removeThreeLinked(tempX,tempY);}if(isThreeLinked(clickX,clickY)){removeThreeLinked(clickX,clickY);                      }downAnimal();updateAnimal();repaint();while(globalSearach(1)){globalSearach(2);downAnimal();updateAnimal();repaint();}}else{//System.out.println("没有可消去的方块");//交换回来help = map[tempX][tempY];map[tempX][tempY] = map[clickX][clickY];map[clickX][clickY] = help;                   }isClick = false;}else{//不相邻或者就是点击的还是自身isClick = true;clickX = tempX;clickY = tempY;drawSelectedBlock(tempY*W+leftX, tempX*W+leftY, this.getGraphics());}}else{isClick = true;clickX = tempX;clickY = tempY;drawSelectedBlock(tempY*W+leftX, tempX*W+leftY, this.getGraphics());}        }

判断map[x][y]处是否存在可消去图案:

使用count变量记录连续相同的图案数目,count=1,先水平方向判断是否存在三个以上相邻图案,如果count>=3则返回true;

否则再重置count=1,从垂直方向判断是否存在三个以上相邻图案,如果count>=3则返回true。

如果还不存在可消去图案,返回false:

 //检测是否存在三个以上相连的方块private boolean isThreeLinked(int x, int y) {int count = 1;if(x+1<n){for(int i=x+1;i<n;i++){if(map[i][y]==map[x][y]){count++;}else{break;}}}if(x-1>=0){for(int i=x-1;i>=0;i--){if(map[i][y]==map[x][y]){count++;}else{break;}}}if(count>=3){return true;}count = 1;if(y+1<n){for(int i=y+1;i<n;i++){if(map[x][i]==map[x][y]){count++;}else{break;}}}if(y-1>=0){for(int i=y-1;i>=0;i--){if(map[x][i]==map[x][y]){count++;}else{break;}}}if(count>=3){return true;}return false;}

消除map[x][y]处三个以上相连的图案:

使用count记录可消去的图案数量,linked作为标记水平方向或竖直方向上相连的图案数量,

先判断竖直方向上相连的图案数量是否>=3,如果是,则消除掉竖直方向相连的图案并且count++;

接着置linked为1,判断水平方向上相连的图案数量是否>=3,如果是,则消除水平方向相连的图案并且count++;

最后置map[x][y]为空,分数+=count*10;

//消除三个以上相连的方块private void removeThreeLinked(int x, int y) {int count = 1;int linked = 1;if(x+1<n){//向下探测for(int i=x+1;i<n;i++){if(map[i][y]==map[x][y]){linked++;}else{break;}}}if(x-1>=0){//向上探测for(int i=x-1;i>=0;i--){if(map[i][y]==map[x][y]){linked++;}else{break;}}}if(linked>=3){//上下相邻超过三个方块for(int i=x-1;i>=0;i--){if(map[i][y]==map[x][y]){count++;map[i][y] = EMPTY;}else{break;}}for(int i=x+1;i<n;i++){if(map[i][y]==map[x][y]){count++;map[i][y] = EMPTY;                  }else{break;}}}linked = 1;if(y+1<n){//向右探测for(int i=y+1;i<n;i++){if(map[x][i]==map[x][y]){linked++;}else{break;}}}if(y-1>=0){//向左探测for(int i=y-1;i>=0;i--){if(map[x][i]==map[x][y]){linked++;}else{break;}}}if(linked>=3){//左右相邻超过三个方块for(int i=y-1;i>=0;i--){if(map[x][i]==map[x][y]){count++;map[x][i] = EMPTY;}else{break;}}for(int i=y+1;i<n;i++){if(map[x][i]==map[x][y]){count++;map[x][i] = EMPTY;}else{break;}}}map[x][y] = EMPTY;score+=count*10;HelpPanel.score.setText(score+"");}

扫描游戏池:

如果flag==1,只判断游戏池中是否存在可消除的图案,如果存在返回true;

否则消除游戏池中可消除的所有图案。

//1扫描是否存在可消除方块//2扫描并消除可消除方块private boolean globalSearach(int flag) {if(flag == 1){for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(isThreeLinked(i, j)){return true;}}}            }else{for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(isThreeLinked(i, j))removeThreeLinked(i, j);}}}return false;}

图案下落填充:
从最后一行向上扫描游戏池,如果数组元素为空,则找到和它同一列,在它上方的第一个非空元素进行交换

 //图案下落private void downAnimal() {for(int i=n-1;i>=0;i--){for(int j=0;j<n;j++){if(map[i][j]==EMPTY){int temp = i;while(temp>=0){if(map[temp][j]!=EMPTY){int help = map[i][j];map[i][j] = map[temp][j];map[temp][j] = help;break;}temp--;}}}}}

更新游戏池状况:

图案下落后,此时空块都位于最上层,可以直接随机生成图案ID赋值给空的数组元素:

 //更新图案数组private void updateAnimal() {for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(map[i][j]==EMPTY){map[i][j] = (int) (Math.random()*(n-2));}}}}

画选中框:

根据左上角x,y像素坐标,画框:

//画选中框private void drawSelectedBlock(int x, int y, Graphics g) {Graphics2D g2 = (Graphics2D) g;//生成Graphics对象BasicStroke s = new BasicStroke(1);//宽度为1的画笔g2.setStroke(s);g2.setColor(Color.RED);g.drawRect(x+1, y+1, 48, 48);}

历史记录读写:

基础的文件IO操作,如果文件不存在自动新建:

//读取历史记录public int getBestScore(){File file = new File("D://GameRecordAboutSwing");if(!file.exists()){file.mkdirs();}File record = new File("D://GameRecordAboutSwing/SupperzzleGame.txt");try{if(!record.exists()){//如果不存在,新建文本record.createNewFile();fos = new FileOutputStream(record);dos = new DataOutputStream(fos);String s = "0";dos.writeBytes(s);}//读取记录fis = new FileInputStream(record);dis = new DataInputStream(fis);String str = dis.readLine();bestScore = Integer.parseInt(str);}catch(Exception e){e.printStackTrace();}finally{try {if(fis!=null)fis.close();if(dis!=null)dis.close();           if(fos!=null)fos.close();if(dos!=null)dos.close();                } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return bestScore;}//更新历史记录public void updateBestScore(){File record = new File("D://GameRecordAboutSwing/SupperzzleGame.txt");try {//清空原有记录FileWriter fileWriter =new FileWriter(record);fileWriter.write("");fileWriter.flush();fileWriter.close();//重新写入文本fos = new FileOutputStream(record);dos = new DataOutputStream(fos);String s = score.getText();bestScore = Integer.parseInt(score.getText());dos.writeBytes(s);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {if(fos!=null)fos.close();if(dos!=null)dos.close();              } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}HelpPanel.record.setText(bestScore+"");}

开始游戏:

设定进度条progress最大值为100,线程每秒自增1,游戏开始时初始化进度条progress并为游戏面板添加鼠标监听和键盘事件,进度条满之后,移除游戏面板的监听并提示玩家游戏成绩,如果当前分数高于历史记录则进行历史记录的更新。

 public MyFrame(){actionPanel.setLayout(new FlowLayout()); actionPanel.add(buttonRestart,BorderLayout.CENTER);this.getContentPane().setLayout(new BorderLayout());this.getContentPane().add(helpPanel,BorderLayout.NORTH);this.getContentPane().add(gamePanel,BorderLayout.CENTER);this.getContentPane().add(actionPanel,BorderLayout.SOUTH);    this.setSize(700,700);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setTitle("对对碰");this.setVisible(true);buttonRestart.addMouseListener(new MouseAdapter(){public void mouseClicked(MouseEvent e){if(flag)return ;flag = true;gamePanel.addKeyListener(gamePanel);gamePanel.addMouseListener(gamePanel);gamePanel.startGame();buttonRestart.setEnabled(false);HelpPanel.score.setText(0+"");new Thread(new Runnable(){@Overridepublic void run() {nowTime = 0;while(true){try {Thread.currentThread().sleep(1000);nowTime++;HelpPanel.setTime(nowTime);if(nowTime==100){gamePanel.removeMouseListener(gamePanel);gamePanel.removeKeyListener(gamePanel);int score = Integer.parseInt(helpPanel.score.getText());int record = Integer.parseInt(helpPanel.record.getText()); if(score>record){JOptionPane.showMessageDialog(null, "游戏结束,你的得分是"+score+",刷新了历史记录"+record);helpPanel.updateBestScore();}else{JOptionPane.showMessageDialog(null, "游戏结束,你的得分是"+HelpPanel.score.getText());}buttonRestart.setEnabled(true);flag = false;break;}} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}).start();;}});}

主要游戏功能到这里已经介绍完毕,玩家可以使用A键打乱游戏池,游戏保证了开始时不存在图案连锁消除的情况。

由于完整源码篇幅过长,这里不再贴出,素材和工程均已上传到网盘。

素材与完整源码链接:https://pan.baidu.com/s/1J1iXvgvVrNZI_Waq3v3xNA 提取码: iefw

Java游戏开发——对对碰相关推荐

  1. 用90%的c语言开发对对碰游戏,希望大家指点哈

    用90%的c语言开发对对碰游戏,希望大家指点哈 **还有部分是c++语言哈**第一次写博客哈,有什么不足望大家指出我能写出来也参考网上的一些代码哈 #include <iomanip> # ...

  2. 【源码+图片素材+详细教程】Java游戏开发_Java开发经典游戏飞翔的小鸟_飞扬的小鸟_Java游戏项目Flappy Bird像素鸟游戏_Java课程设计项目

    课程目标: 1.通过本课程的学习巩固Java的相关基础知识,例如循环判断,数组和集合的使用,对象的继承,接口的实现,窗口的创建,事件监听,图形绘制. 2.完成小鸟的移动,管道自动生成.碰撞死亡,计分系 ...

  3. java游戏开发杂谈 - 实现游戏主菜单

    经常玩游戏的同学,大家都知道,游戏都会有个主菜单,里面有多个菜单选项:开始游戏.游戏设置.关于游戏.退出游戏等等,这个菜单是怎么实现的呢. 有一定桌面软件开发基础的同学可能会想到,用JButton组件 ...

  4. java游戏开发杂谈 - 游戏编程浅析

    每个游戏,你所看到的它的一切,都是计算机画出来的! 地图是画出来,人物是画出来的,树木建筑是画出来的,菜单按钮是画出来的,滚动的文字.闪烁的图标.云雾烟火,都是画出来的. 游戏编程,所要做的,就是控制 ...

  5. java游戏开发入门(十) -粒子特效

    java游戏开发入门十 - 粒子特效 java游戏开发入门十 - 粒子特效 前言 编码 创建一个粒子发射器,并将粒子发射器添加到实体对象 效果图 完整代码 完整项目 java游戏开发入门十 - 粒子特 ...

  6. Java游戏开发组件LGame简易测试版发布(版本号 0 1 5)

    LGame-Simple-0.1.5组件下载地址:http://code.google.com/p/loon-simple/downloads/list 2009-09-13 更新内容: Java游戏 ...

  7. 三七互娱 Java游戏开发工程师 面试(两轮技术+HR面)

    (2020春招补招,已拿到offer) 抱着投着试试看的心态去的 自己还是不太了解游戏开发 框架啊这些都没怎么问 比较重视基础知识,面的也基本都是基础知识 所以面完才发现自己太基础的知识反而一问三不知 ...

  8. java游戏开发入门(二) - 菜单

    java游戏开发入门(二) - 菜单 前言 编码 主菜单 游戏内菜单(按下ESC后出现,并会暂停游戏) 效果展示 主菜单 游戏内菜单 完整代码 完整项目 前言   上一章我们创建了一个600x600的 ...

  9. 【11款最全最新】Java游戏开发项目合集_Java项目实战_Java练手项目

    黄金矿工.俄罗斯方块.飞机大战.超级玛丽.坦克大战.飞翔的小鸟.扫雷.王者荣耀.推箱子.贪吃蛇.大鱼吃小鱼这些经典小游戏相信很多人都玩过.那大家有没有想过亲自制作出这些小游戏呢? 下面就给大家分享这1 ...

最新文章

  1. 五年12篇顶会论文综述!一文读懂深度学习文本分类方法
  2. CIO成功转型为战略性业务领导者的五个要领
  3. C# ArrayList集合
  4. hdu 2196(经典树形dp)
  5. JMeter正则表达式-学习(3)
  6. SAP CRM WebClient UI和Hybris Commerce的懒加载机制
  7. 曦智科技发布最新光子计算处理器PACE
  8. java 调用 .net dll_c# – 如何从Java调用.NET dll
  9. Android学习笔记(九)——更复杂的进度对话框
  10. ubuntu 16.04安装网易云音乐
  11. JAVA入门学习 —数组排序的方法
  12. 服务器lsass占用内存_记一次服务器病毒查杀过程:lsass.exe占用内存高
  13. java 支付宝 验证签名失败,关于支付宝签名校验失败的问题排解
  14. Android stuido中更改图片编辑软件
  15. 想找Java项目练手,却不知道从哪找?
  16. 第五人格手机游戏在PC上怎么玩?第五人格哪款模拟器好用?
  17. 西门子1200plc485轮询读写28个测试仪表,包括plc程序和触摸屏程序
  18. 4.11 Lewis Carroll等式
  19. python 爬取淘宝第一弹(淘宝登录)
  20. python爬虫报错: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]

热门文章

  1. -- 44、检索至少选修两门课程的学生学号
  2. bzoj 4605 崂山白花蛇草水
  3. 洛谷 | P1226 【快速幂】
  4. 大数据分析R中泊松回归模型实例
  5. single-row subquery returns more than one row
  6. 11款Windows必装软件,每一款都非常好用
  7. Python快速幂算法实现
  8. GSI-ECM工程建设管理数字化平台
  9. 故障分析 | Cassandra 用户信息 list Error
  10. 一位大龄程序员所经历的面试的历炼和思考