连连看项目
一、前期准备:
1、若干种大小相同的图片,图片最好以数字命名,这样便于随机参数图片。
2、数据结构
由于我们需要每次根据鼠标的坐标定位每张图片位置,所以我们每张图片的大小需要固定
而且采用数组来存放图片,这样容易根据鼠标坐标来定位图片的下标。
3、对于一些固定的数据,最好写在一个接口中,或者写在XML文件中,写在xml文件中
便于程序发布之后对数据的更改,写在接口中,每个类只需要实现这个接口,就可以获得
这个接口中的所有配置数据,比如,行数、列数、图片大小、起始点的坐标等等数据。
4、设计要求:不大于两个弯道可以联通就可以消除,需要画出消除的路径,需要提示当前选中的图片。
二、实现步骤:
1、给图片数组赋值,每种图片都是偶数个的实现:
首先需要明白,练练看中的图片必须是成对出现,每一种图片的个数必须是偶数。
(1、)我们利用一个队列来存放我们需要画在游戏面板中的图片,队列的自动增减长度的特性我们接下来需要用到,所以这里需要用队列。
第一步:随机产生图片,每次产生一个图片,我们都将它往队列中插入两次,这样就保证了每种图片的个数是偶数。
ArrayList<ImageIcon> arrs = new ArrayList<ImageIcon>(); Random random= new Random(); for (int i = 0; i < ROWS * COLS / 2; i++) { int num = random.nextInt(5); // 构建图片路径 String str = "images/" + num + ".gif"; ImageIcon image = new ImageIcon(str); // 将图片放入队列,每次放两次 arrs.add(image); arrs.add(image); }
第二步:我们在游戏面板中画出图片的时候,每次从队列中随机取出一张图片,这个随机数的大小就是队列的大小,取出后我们就从队列中将它移除,这样队列的长度就减小了,我们下次再从队列的大小来产生随机数,这样就实现了随机取出。
for (int j = 0; j < COLS; j++) {
// 从队列中,随机取出一个数并移除,移除后队列的大小会自动改变
int index = random.nextInt(arrs.size());
//给图片数组赋值
images[i][j] = arrs.remove(index);
}
}
2、在游戏面板中画出图片数组中的图片。
注意:这里需要根据图片的下标,来计算出图片的左上角的坐标。
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (images[i][j] != null) {
g.drawImage(images[i][j].getImage(), X0 + j * SIZE, Y0
+ i * SIZE, null);
}
}
}
}
}
3、消除的实现
(1)同行的消除,鼠标每点击一次,就根据鼠标的坐标算出该图片的下标,当点击第二次的时候,将两个图片进行对比,先看是不是同一行,也就是r值否相同,再看两个图片是否是同一种类型的图片,再判断这两张图片中间的所有图片是不是为空(我们消除图片,就是将图片数组中对应的图片对象赋值为空)
注意:如果两次点击的是同一张图片,我们也不做处理
下面的代码,先判断鼠标是不是在有效范围内点击,而且两次点击的是不是同一图片,如果满足,我们再调用比较函数,比较这两个图片再同一行是不是能够消除。
//得到事件源,由于监听器是加载在游标面板上,所以事件源就是面板 final GamePanel gp = (GamePanel) e.getSource(); x1=e.getX(); y1=e.getY(); //每次选中一个图片都,在这个图片外围画一个框,提示该图片被选中 //得到该图片左上角的坐标 if((x1>=X0&&y1>=Y0)&&(x1<=(COLS*SIZE+X0)&&y1<=(ROWS*SIZE+Y0))){ System.out.println("点"+x1); System.out.println("边际"+(COLS*SIZE+X0)); int xp=((x1-X0))/SIZE*SIZE+X0; int yp=((y1-X0))/SIZE*SIZE+Y0; g.drawRect(xp, yp, SIZE, SIZE); //第一次 if(count==0){ icon1=getImage(x1,y1); //根据坐标获得数组下标,L,R C01=(x1-X0)/SIZE; R01=(y1-Y0)/SIZE; count=1; }else{ x2=e.getX(); y2=e.getY(); icon2=getImage(x2,y2); //通过x算出的是第几列 C02=(x2-X0)/SIZE; R02=(y2-Y0)/SIZE; //如果图标都不为空,且是相同图片,则让这两张图片为空。 if((C01!=C02||R01!=R02)&&icon1!=null&&icon2!=null&&icon1.toString().equals(icon2.toString())){ if(Suanfa.checkCol(C01, R01, C02, R02)||Suanfa.checkRow(C01, R01, C02, R02) ||Suanfa.checkZhuan01(C01, R01, C02, R02) ||Suanfa.checkZhuan02(C01, R01, C02, R02) ){ //启动一个线程来消除图片 //先将连接线画出来,再将图片消除 for(int i=0;i<GamePanelListener.list.size();i+=2){ Point p1=GamePanelListener.list.get(i); Point p2=GamePanelListener.list.get(i+1); g.drawLine(p1.x, p1.y, p2.x, p2.y); } //将队列清空 GamePanelListener.list.clear(); try { Thread.sleep(1000); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } images[R01][C01]=null; images[R02][C02]=null; icon1=null; icon2=null; gp.repaint(); } } gp.repaint(); count=0; } }
检查再同一行是不是能够消除:
//参数是数组的下标 public static boolean checkRow(int C1,int R1,int C2,int R2){ //同一行,说明是x的下标相同 if(R1==R2){ //找出y1和y2的最大值和最小值 int min = Math.min(C1, C2); int max = Math.max(C1, C2); //从min+1到max-1遍历 for(int i =min+1;i<max;i++){ //如果有不为空,直接返回false,如果,这里一直没有返回false,就说明都是空,最后返回true if(images[R1][i]!=null){ return false; } } //每次将可以消除的行加入队列 //这里将下标转为图片中心点的坐标 int x1=X0+C1*SIZE+SIZE/2; int y1=Y0+R1*SIZE+SIZE/2; int x2=X0+C2*SIZE+SIZE/2; int y2=Y0+R2*SIZE+SIZE/2; GamePanelListener.list.add(new Point(x1,y1)); GamePanelListener.list.add(new Point(x2,y2)); System.out.println("行可消除"); return true; } return false; }
检查在同一列是不是可以消除:
public static boolean checkCol(int C1,int R1,int C2,int R2){ //同一行,说明是x的下标相同 if(C1==C2){ //找出y1和y2的最大值和最小值 int min = Math.min(R1, R2); int max = Math.max(R1, R2); //从min+1到max-1遍历 for(int i =min+1;i<max;i++){ //如果有不为空,直接返回false,如果,这里一直没有返回false,就说明都是空,最后返回true if(images[i][C1]!=null){ return false; } } int x1=X0+C1*SIZE+SIZE/2; int y1=Y0+R1*SIZE+SIZE/2; int x2=X0+C2*SIZE+SIZE/2; int y2=Y0+R2*SIZE+SIZE/2; GamePanelListener.list.add(new Point(x1,y1)); GamePanelListener.list.add(new Point(x2,y2)); System.out.println("列可消除"); return true; } return false; }
4、如果同行同列可以消除了,下面的也就简单了。
首先是转一个弯道的情况,其实也就是在比较三个点是不是两两可以同行或者同列可以消除,
关键是我们要找出那个转折点,转一个弯道,那个转折点,应该和需要消除的两个点,在同行或者同列,
也就是一个矩形的另外两个,只需要将这两个点分别拿来和需要消除的点比较是不是同列可消除并且同行可以消除,并且自己是为空的,那么就实现了转一个弯道。
// 有一个转折点的 public static boolean onePoint(int r1, int c1, int r2, int c2) { // 转折点为r1c2 if (ICONS[r1][c2] == null) { if (checkRow(r1, c1, r1, c2) && checkCol(r2, c2, r1, c2)) { return true; } } // 转折点为r2c1 if (ICONS[r2][c1] == null) { if (checkRow(r2, c2, r2, c1) && checkCol(r1, c1, r2, c1)) { return true; } } GamePanelListener.list.clear(); return false; }
5、转两个弯道,转两个弯道分为水平的情况和垂直的情况,
水平的时候,两个转折点和需要消除的两个点在同一行,这两个转折点是在同一列的,这两个转折点从最左边一起平移到最右边,比较完所有情况。
// 水平移动 public static boolean twoPointH(int r1, int c1, int r2, int c2) { // 定义一个变量表示两个转折点的列下标 for (int i = 0; i < COLS; i++) { // 转折点为r1,i和r2,i if (ICONS[r1][i] == null && ICONS[r2][i] == null) { if (checkRow(r1, i, r1, c1) && checkRow(r2, i, r2, c2) && checkCol(r1, i, r2, i)) { return true; } } } GamePanelListener.list.clear(); return false; }
垂直的也是一样的,转折的两个点在同一样,从上到下平移所有情况。
// 垂直移动 public static boolean twoPointV(int r1, int c1, int r2, int c2) { for (int i = 0; i < ROWS; i++) { if (ICONS[i][c1] == null && ICONS[i][c2] == null) { if (checkRow(i, c1, i, c2) && checkCol(r1, c1, i, c1) && checkCol(r2, c2, i, c2)) { return true; } } } GamePanelListener.list.clear(); return false; }
6、画出连接路径:
每次在可以消除的时候,都是比较了两个点同行或者同列的时候,如果可以消除,每次比较的这个两个点是必须要画线的,那么我们每次将这两个点添加到队列中,画线的时候就画出这两个点之间的线
比如1,2和3,4 但是注意2,3不能画线,因为,1,2是一个比较组,3,4是一个比较组,2,3之间是不需要画线的。
还要特别注意一点,我们比较行或者列可以消除之后就将对于的点加到了队列,但是比如需要转两个点,我们就需要判断三次,如果前面两次满足,后面一个不满足,那么我们就将不满足的也添加到了画线的点的队列中,这样就会出错,所以,我们在判断其转一个点和两个点的时候,如果最后的结果是不满足,那么我们就要将画线的点的队列清空,清楚掉刚才满足部分条件添加到队列中的点。
这样只需要在检查行和列中添加一段代码,
int x1=X0+C1*SIZE+SIZE/2; int y1=Y0+R1*SIZE+SIZE/2; int x2=X0+C2*SIZE+SIZE/2; int y2=Y0+R2*SIZE+SIZE/2; GamePanelListener.list.add(new Point(x1,y1)); GamePanelListener.list.add(new Point(x2,y2));
在一个转折点中和两个转折点中添加一段代码。
GamePanelListener.list.clear();
7、提示框,这个只需要根据鼠标坐标计算出该图片左上角的点,在画出一个矩形框就可以了
int yp=((y1-X0))/SIZE*SIZE+Y0;
g.drawRect(xp, yp, SIZE, SIZE);
相关推荐
本篇文章将探讨如何利用人工智能技术来实现连连看游戏的自动解谜程序,以及分析此类程序代码的设计思路。 一、连连看游戏规则与策略 连连看的基本规则是找到两个相同的图案,并通过一条没有其他图案阻隔的直线将其...
总结,这个基于Java的连连看游戏系统设计与实现项目,不仅展示了Java在游戏开发中的实际应用,也提供了一个学习和实践的平台。通过分析项目材料,不仅可以提升Java编程能力,还能掌握游戏开发的基本流程和技术要点。
在这个项目中,我们重点讨论的是使用MFC(Microsoft Foundation Classes)框架开发的宠物连连看源代码,以及相关的实验技术文档和实验报告。 MFC是微软提供的一套C++类库,用于构建Windows应用程序。它封装了...
项目报告是整个项目完成后的总结,通常包括项目目标、设计思路、实现过程和遇到的问题及解决方案。阅读项目报告能帮助孩子了解一个完整的编程项目从构思到实现的全过程,提高他们解决问题的能力。 教师参考程序和...
5. **设计文档**:编写设计文档,包括问题描述、设计思路、代码实现和测试报告。 **二、开发环境和技术** 1. **开发工具**:使用Eclipse、NetBeans或JBuilder等集成开发环境。 2. **技术栈**:基于Java核心API,...
5. **总结与反思**:对项目成果的总结,可能的优化方向,以及对学习过程的个人感悟。 通过阅读实验报告,我们可以深入了解开发者如何将理论知识应用于实际项目,理解游戏开发的全过程,从而提升自己的编程技能。 ...
本篇文章将深入探讨如何利用Android平台开发一款完整的连连看游戏,结合给定的“连连看android版完整代码”,我们将详细介绍其设计思路、主要功能实现以及关键技术。 首先,我们需要理解连连看的基本规则:玩家需要...
总结,VB小游戏连连看是一个集成了VB基本编程技巧、游戏逻辑设计和用户体验优化的综合性项目。通过研究这个项目,不仅可以提升VB编程技能,还能学习到游戏开发的基本流程和方法,对于想要进入游戏开发领域的初学者来...
《深入解析连连看游戏开发:基于J2ME的实现与算法》 连连看,作为一款深受大众喜爱的...通过学习和研究这个Demo,不仅可以了解连连看游戏的设计思路,还能掌握J2ME平台的开发技术,为今后的移动应用开发打下坚实基础。
对于希望学习或提升Java编程技能的开发者而言,这份源码提供了一个宝贵的实践案例,有助于理解Java语言在具体项目中的运用,同时也为游戏开发提供了参考思路。通过学习此类代码,开发者可以更好地掌握Java的类库使用...
总结,这款Java连连看小游戏,不仅是一个娱乐项目,更是一个教学工具,通过实际操作,帮助开发者提高编程技能,理解游戏开发的基本流程和关键技巧。无论是自娱自乐还是学习研究,都是非常值得尝试的。
总结来说,“c语言连连看游戏源码”是一个实践与理论相结合的学习资源,它将C语言的基本元素与游戏开发的实践紧密结合,为学习者提供了丰富的学习素材。通过仔细研究源码,不仅可以深入理解C语言,还能掌握游戏开发...
在本资源中,我们主要探讨的是一个使用Java Swing库开发的连连看游戏的GUI实现,包括源代码、相关论文和教学视频。以下是关于这个项目的详细知识点: 1. **Java Swing**: Swing是Java的一个图形用户界面(GUI)工具包...
总结来说,C#开发的连连看游戏是一个综合性的项目,它涉及到图形界面设计、算法实现、数据结构运用、用户体验优化等多个方面。通过这个项目,开发者不仅可以深入学习C#编程,还能提升游戏开发的实战技能。对于初学者...
本篇文章将深入探讨一个基于C#的连连看游戏源码,分析其设计思路、核心技术和可扩展性,为学习游戏编程的朋友们提供宝贵的参考。 首先,我们来了解一下这个游戏的基本信息。标题“C# 做的连连看源码”表明这是一个...
- 面向对象设计:连连看游戏中的每个元素(如游戏方块、匹配规则等)都可以抽象为类,通过继承和多态性实现代码的复用和扩展。 2. **图形用户界面(GUI)** - Java提供Swing和JavaFX等库用于创建图形用户界面。在...
感谢指导老师禹沈清在整个项目期间给予的帮助和支持,同时也感谢同行们的交流与分享,使得本次项目得以顺利完成。 ### 附录 - **主界面的设计**:主界面简洁大方,主要包括开始游戏按钮、游戏规则介绍等元素。 - *...
10. **报告书**:报告书通常包括项目的背景、目标、设计思路、技术实现、测试结果等内容,可以帮助读者了解整个开发过程,对开发者来说是一种宝贵的反思和总结。 通过这个项目,开发者不仅可以学习到Java Swing的...