连连看大家应该都玩过,不多说直接上一个做好的界面截图吧,所有的功能都在上面的,要做的就只是如何去实现它们了。

差不多就是这个样子。先说一下大致的思路吧。首先编写基本的界面:把什么按钮啊,表格啊什么的都画上去。然后就是编写事件处理类,因为操作使用鼠标,所以加上鼠标监听。然后获取点击的坐标,根据坐标得出图片在数组中的位置。接着创建一个类,实现连连看消除的算法。这样就基本上可以开始游戏了。然后实现排行榜按钮和存档按钮的基本功能。最后加上一个线程类,用于处理倒计时。下面的介绍也基于这个顺序。

界面实现:这个其实没什么好说的,把JFrame的知识用上就好了。考虑到图片的闪烁问题,在界面类中重写paint方法,加上双缓冲(双缓冲不懂的,可以自行百度或者看看我写的Java版本2048)。所以就直接贴代码了。

package com.cbs.look;public interface LookConfig {int x=50;//初始x坐标,原来是10int y=100;//初始y坐标,原来是50int space=10;//图片间的间隔int arc=50;//圆角矩形的弧度int size=60;//图片的大小int num=9;//图片类型
}
package com.cbs.look;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;/*** 连连看的主界面类* * @author CBS* */
@SuppressWarnings("serial")
public class GameLook extends JFrame implements LookConfig {private int[][] array = new int[8][8];// 数组用于保存界面的信息JLabel timeJl;// 用于显示剩余时间public static void main(String[] args) throws InterruptedException {GameLook g = new GameLook();g.showUI();}/*** 初始化界面* * @throws InterruptedException*/public void showUI() throws InterruptedException {setTitle("连连看");setSize(700, 800);setDefaultCloseOperation(3);setLocationRelativeTo(null);setResizable(true);setLayout(null);// 添加新游戏按钮
//        ImageIcon start = new ImageIcon("res/start.png");JButton startJB = new JButton("新游戏");startJB.setBounds(30, 700, 100, 40);
//        startJB.setBorderPainted(false);// 设置边框为空startJB.setFocusable(false);
//        startJB.setContentAreaFilled(false);// 设置内容空this.add(startJB);// 添加排行榜按钮JButton save = new JButton("排行榜");save.setFocusable(false);save.setBounds(190, 700, 100, 40);this.add(save);// 添加存档按钮JButton saveGame = new JButton("存档");saveGame.setFocusable(false);saveGame.setBounds(320, 700, 100, 40);this.add(saveGame);// 添加剩余时间JLabel jl = new JLabel("Time:");jl.setFont(new Font("", Font.BOLD, 20));jl.setBounds(440, 700, 80, 50);this.add(jl);// 显示剩余时间timeJl = new JLabel("90");timeJl.setFont(new Font("", Font.BOLD, 20));timeJl.setBounds(520, 700, 80, 50);this.add(timeJl);setVisible(true);GameListener gl = new GameListener();gl.setFrame(this);gl.setTimeJl(timeJl);gl.setArray(array);saveGame.addActionListener(gl);startJB.addActionListener(gl);save.addActionListener(gl);int i=JOptionPane.showConfirmDialog(this, "是否读取上次的存档", "读档",JOptionPane.YES_NO_OPTION);if(i==1){JOptionPane.showMessageDialog(this, "请按新游戏开始游戏吧!");}else{GameSave2 gs2=new GameSave2();CunD c=gs2.opean();if(c!=null){array=c.getArray();gl.setArray(array);this.addMouseListener(gl);this.repaint();TimeOut tt =new TimeOut(timeJl, this, gl);gl.setTt(tt);tt.setSeconds(c.getTime());tt.start();}else{JOptionPane.showMessageDialog(this, "读取失败!");}}}@Overridepublic void paint(Graphics g) {super.paint(g);buffPaint(g);}/*** 使用双缓冲技术解决闪屏问题* * @param g传入的画笔对象*/public void buffPaint(Graphics g) {Image i = createImage(space + (size + space) * array[0].length, space+ (size + space) * array.length);Graphics2D g2d = (Graphics2D) i.getGraphics();g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);// 绘制背景矩形g2d.setColor(new Color(210, 180, 140));g2d.fillRoundRect(0, 0, space + (size + space) * array[0].length, space+ (size + space) * array.length, arc, arc);// 绘制背景方格g2d.setColor(new Color(245, 245, 220));for (int r = 0; r < array.length; r++) {for (int c = 0; c < array[r].length; c++) {g2d.fillRect(space + (size + space) * c, space + (size + space)* r, size, size);}}// 绘制图片g2d.setColor(Color.BLUE);g2d.setFont(new Font("宋体", Font.BOLD, 30));for (int r = 0; r < array.length; r++) {for (int c = 0; c < array[r].length; c++) {if (array[r][c] != 0) {ImageIcon icon = new ImageIcon("res/" + array[r][c]+ ".jpg");Image image = icon.getImage();g2d.drawImage(image, space + (size + space) * c, space+ (size + space) * r, size, size, null);}}}g.drawImage(i, x, y, this);}
}

事件处理类:鼠标的事件处理主要负责的是记录两次点击的坐标,然后判断是否能够把两个图片消除,如果可以消除图片把对应的数组位置的数置为0,然后重绘画板,如果不行同样重绘画板消除选框及连线。动作的事件处理主要负责实现不同的按钮的功能。

package com.cbs.look;import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Random;import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.plaf.FontUIResource;
/*** 事件处理类* @author CBS*/
public class GameListener extends MouseAdapter implements LookConfig,ActionListener {// 用于控制坐标的获取private boolean flag = true;private int r1, c1, r2, c2;// 对应数组的下标位置private int x1, y1, x2, y2;// 鼠标点击的坐标private int array[][];// 保存数组private JFrame frame;// 用于获取窗体对象,调用Repaint方法private Graphics2D g;// 画笔对象JLabel timeJl;// 用于显示剩余时间TimeOut tt ;// 倒计时线程类private int x;// 保存画框的顶点x坐标private int y;// 保存画框的顶点y坐标public TimeOut getTt() {return tt;}public void setTt(TimeOut tt) {this.tt = tt;}public void setTimeJl(JLabel timeJl) {this.timeJl = timeJl;}public void setFrame(JFrame frame) {this.frame = frame;g = (Graphics2D) frame.getGraphics();}public void setArray(int[][] array) {this.array = array;}@Overridepublic void mousePressed(MouseEvent e) {// 获取坐标if (flag) {x1 = e.getX() - 40;y1 = e.getY() - 50;flag = false;if (y1 / (size + space) - 1 >= array.length)r1 = array.length - 1;else if (y1 / (size + space) - 1 < 0)r1 = 0;elser1 = y1 / (size + space) - 1;if (x1 / (size + space) >= array[0].length)c1 = array[0].length - 1;elsec1 = x1 / (size + space);g.setColor(Color.RED);g.setStroke(new BasicStroke(5));x = space + space + c1 * (size + space) + 40;y = size + r1 * (size + space) + 50;g.drawRect(x, y, size, size);} else {x2 = e.getX() - 40;y2 = e.getY() - 50;flag = true;if (y2 / (size + space) - 1 >= array.length)r2 = array.length - 1;else if (y1 / (size + space) - 1 < 0)r1 = 0;elser2 = y2 / (size + space) - 1;if (x2 / (size + space) >= array[0].length)c2 = array[0].length - 1;elsec2 = x2 / (size + space);g.setColor(Color.RED);g.setStroke(new BasicStroke(4));x = space + space + c2 * (size + space) + 40;y = size + r2 * (size + space) + 50;g.drawRect(x, y, size, size);}GameUtil gu = new GameUtil(this.frame);if (array[r1][c1] == array[r2][c2] && flag && !(r1 == r2 && c2 == c1)&& (array[r1][c1] != 0 || array[r2][c2] != 0)) {if (gu.wuZhe(r1, c1, r2, c2, array)) {array[r1][c1] = 0;array[r2][c2] = 0;g.setColor(Color.PINK);g.drawLine(2 * space + size / 2 + c2 * (size + space) + 40,size + size / 2 + r2 * (size + space) + 50, 2 * space+ size / 2 + c1 * (size + space) + 40, size+ size / 2 + r1 * (size + space) + 50);} else if (gu.yiZhe(r1, c1, r2, c2, array)) {array[r1][c1] = 0;array[r2][c2] = 0;g.setColor(Color.PINK);g.drawLine(2 * space + size / 2 + gu.getPath().get(0).y* (size + space) + 40, size + size / 2+ gu.getPath().get(0).x * (size + space) + 50, 2* space + size / 2 + c1 * (size + space) + 40, size+ size / 2 + r1 * (size + space) + 50);g.drawLine(2 * space + size / 2 + gu.getPath().get(0).y* (size + space) + 40, size + size / 2+ gu.getPath().get(0).x * (size + space) + 50, 2* space + size / 2 + c2 * (size + space) + 40, size+ size / 2 + r2 * (size + space) + 50);} else if (gu.erZhe(r1, c1, r2, c2, array)) {array[r1][c1] = 0;array[r2][c2] = 0;g.setColor(Color.PINK);g.drawLine(2 * space + size / 2 + gu.getPath().get(1).y* (size + space) + 40, size + size / 2+ gu.getPath().get(1).x * (size + space) + 50, 2* space + size / 2 + c1 * (size + space) + 40, size+ size / 2 + r1 * (size + space) + 50);// path的下标为一的位置要减一,因为数组扩大了g.drawLine(2 * space + size / 2 + (gu.getPath().get(0).y - 1)* (size + space) + 40, size + size / 2+ (gu.getPath().get(0).x - 1) * (size + space) + 50, 2* space + size / 2 + gu.getPath().get(1).y* (size + space) + 40, size + size / 2+ gu.getPath().get(1).x * (size + space) + 50);g.drawLine(2 * space + size / 2 + (gu.getPath().get(0).y - 1)* (size + space) + 40, size + size / 2+ (gu.getPath().get(0).x - 1) * (size + space) + 50, 2* space + size / 2 + c2 * (size + space) + 40, size+ size / 2 + r2 * (size + space) + 50);}//实现消除控制重绘的刷新时间Thread t=new Thread();try {t.sleep(100);frame.repaint();} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}if (isWin(array)) {tt.setFlag(false);frame.removeMouseListener(this);JOptionPane.showMessageDialog(frame, "恭喜你,"+ "你赢了!!请点击新游戏开始新一局");int i = JOptionPane.showConfirmDialog(frame, "是否记录将你的信息记入排行榜","排行榜", JOptionPane.YES_NO_OPTION);if (i == 0) {String str = JOptionPane.showInputDialog(frame, "请输入你的名字","排行榜", JOptionPane.YES_NO_OPTION);int time=90-tt.getSeconds();User u = new User(str, time);GameSave gs = new GameSave();gs.save(u);}}}//未实现消除,重绘去掉线条if (flag) {Thread t=new Thread();try {t.sleep(100);frame.repaint();} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}}// 按钮动作监听public void actionPerformed(ActionEvent e) {String str = e.getActionCommand();if ("新游戏".equals(str)) {for (int r = 0; r < array.length; r++)for (int c = 0; c < array[r].length; c++)if (array[r][c] != 0) {array[r][c] = 0;}if(tt!=null){if(tt.isFlag()){frame.removeMouseListener(this);tt.setFlag(false);}}randomData();frame.repaint();frame.addMouseListener(this);// 启动线程tt = new TimeOut(timeJl, frame, this);if(!tt.isFlag())tt.setFlag(false);tt.start();}if ("排行榜".equals(str)) {GameSave gs = new GameSave();List<User> list = gs.opean();for (int i = 0; i < list.size(); i++) {int flag = i;for (int j = i + 1; j < list.size(); j++) {if (list.get(i).getTime() > list.get(j).getTime())flag = j;}if (flag != i) {User u1 = list.get(i);User u2 = list.get(flag);list.set(i, u2);list.set(flag, u1);}}JFrame jf = new JFrame();jf.setTitle("排行榜");jf.setDefaultCloseOperation(2);jf.setSize(300, 500);FlowLayout fl = new FlowLayout(FlowLayout.LEFT);jf.setLayout(fl);jf.setLocationRelativeTo(null);for (int i = 0; i < list.size(); i++) {JLabel jl = new JLabel(list.get(i).toString());jl.setFont(new FontUIResource("楷体", Font.BOLD, 20));jf.add(jl);}jf.setVisible(true);}if("存档".equals(str)){System.out.println(23333);GameSave2 gs2=new GameSave2();int time=tt.getSeconds();CunD c=new CunD(array, time);boolean is=gs2.save(c);if(is)JOptionPane.showMessageDialog(frame, "存档成功!");elseJOptionPane.showMessageDialog(frame, "存档失败!");}}/*** 生成随机数字*/public void randomData() {Random random = new Random();int r1, r2, c1, c2;for (int i = 0; i < array.length * array[0].length / 2; i++) {do {r1 = random.nextInt(array.length);c1 = random.nextInt(array[r1].length);} while (array[r1][c1] != 0);array[r1][c1] = random.nextInt(num) + 1;do {r2 = random.nextInt(array.length);c2 = random.nextInt(array[r2].length);} while (array[r2][c2] != 0);array[r2][c2] = array[r1][c1];}}//遍历数组,判断输赢public boolean isWin(int[][] array) {for (int r = 0; r < array.length; r++)for (int c = 0; c < array[r].length; c++)if (array[r][c] != 0)return false;return true;}
}

这里的图片我使用的是直接绘制图片,而不是通过按钮,所以坐标的判断有些麻烦。数组的下标取得是通过鼠标坐标整除方格的边长加间隔,然后由数组下标取得屏幕坐标则相反。初始数据是由randomData方法生成,不同的数字对应不同的图片。

连连看的算法:这里我使用的算法是比较容易理解和实现的分类算法,据说还有一种比较厉害的算法叫广度优先搜索,那个我不会,所以就只能用这种了。先说说连连看的规则吧,就是用不超过两次拐弯的直线能够相连就能够消除。这样分类算法就很好理解了,按照消除要拐弯的次数分为无折相连,一折相连和二折相连。首先是无折相连这个很好理解,要么他们左右相邻或者是上下相邻,要么就是同一行,两个方快中间没有阻隔或者是同一列中间没有阻隔。

就像上面的图,左边是不相邻的,右边是相邻的,这两种都属于无折的相连。然后是一折的相连。一折的相连就是拐一个弯,先看看示意图把:

其实无论是哪种情况,能够实现一折相连的方块都是在矩形的两个对顶角,所以只要判断矩形的另外两个对顶角是否能够实现无折相连就行了。最后是二折相连,同样是先看示意图:

二折的情况看似复杂,其实只要在水平方向上和垂直方向上分别进行遍历,如果是空格就判断这个空格是否能够和另一个格子一折相连就行了。其实整个算法有点像是递归,一折调用无折,二折调用一折。算法的思路大概就是这样。然后就上代码吧:

package com.cbs.look;import java.awt.Point;
import java.util.ArrayList;
import java.util.List;import javax.swing.JFrame;/*** 核心算法* 判断两个方块是否联通* @author CBS* */
public class GameUtil implements LookConfig {//path主要是记录下相连的数组的位置,为了方便实现连线的功能private List<Point> path=new ArrayList<Point>();public List<Point> getPath() {return path;}public GameUtil(JFrame frame) {}/*** 无折算法,无折的情况,要么同行,判断列是否连通;要么同列判断行是否连通* * @param r1第一个方块行下标* @param c1第一个方块列下标* @param r2第二个方块行下标* @param c2第二个方块列下标* @param array用于保存数组的信息* @return 如果能够连通返回TRUE,or返回FALSE*/public boolean wuZhe(int r1, int c1, int r2, int c2, int[][] array) {if (r1 != r2 && c1 != c2)return false;// 如果两点的x坐标相等,则在水平方向上扫描if (r1 == r2) {if (c1 == c2 - 1 || c2 == c1 - 1)// 列相邻return true;for (int i = Math.min(c1, c2) + 1; i < Math.max(c2, c1); i++)if (array[r1][i] != 0)return false;}// 如果两点的y坐标相等,则在竖直方向上扫描else if (c1 == c2) {if (r1 == r2 - 1 || r2 == r1 - 1)// 行相邻return true;for (int i = Math.min(r1, r2) + 1; i < Math.max(r2, r1); i++)if (array[i][c1] != 0)return false;}return true;}/*** 一折算法,无论是哪种情况下,都只需要判断对角的r1,c2和r2,c1和两点是否连通* * @param r1第一个方块行下标* @param c1第一个方块列下标* @param r2第二个方块行下标* @param c2第二个方块列下标* @param array 用于保存数组的信息* @return 如果能够连通返回TRUE,or返回FALSE*/public boolean yiZhe(int r1, int c1, int r2, int c2, int[][] array) {// 如果属于0折的情况,直接返回FALSEif (r1 == r2 || c1 == c2)return false;// 测试对角点1if (array[r1][c2] == 0) {boolean test1 = wuZhe(r1, c1, r1, c2, array);boolean test2 = test1 ? wuZhe(r1, c2, r2, c2, array) : test1;if (test1 && test2){path.add(new Point(r1,c2));return true;}}// 测试对角点2if (array[r2][c1] == 0) {boolean test1 = wuZhe(r1, c1, r2, c1, array);boolean test2 = test1 ? wuZhe(r2, c1, r2, c2, array) : test1;if (test1 && test2){path.add(new Point(r2,c1));return true;}}return false;}/*** 二折算法* * @param r1第一个方块行下标* @param c1第一个方块列下标* @param r2第二个方块行下标* @param c2第二个方块列下标* @param array用于保存数组的信息* @return 如果能够连通返回TRUE,or返回FALSE*/public boolean erZhe(int r1, int c1, int r2, int c2, int[][] array) {//在原来数组的基础上扩大一圈,用于判断边界的方格int[][] newArray = new int[array.length + 2][array[0].length + 2];for (int r = 0; r < array.length; r++) {for (int c = 0; c < array[r].length; c++) {newArray[r + 1][c + 1] = array[r][c];}}//判断是否二折连接// 向下垂直遍历for (int i = r1 + 2; i < newArray.length; i++) {if (newArray[i][c1+1] == 0 ) {if(yiZhe(r2+1, c2+1, i, c1+1, newArray)){path.add(new Point(i-1, c1));return true;}}elsebreak;}// 向上垂直遍历for (int i = r1 ; i > -1; i--) {if (newArray[i][c1+1] == 0  ){if(yiZhe(i, c1+1, r2+1, c2+1, newArray)){path.add(new Point(i-1, c1));return true;}}elsebreak;}// 向右水平遍历for (int i = c1 + 2; i < newArray[0].length; i++) {if (newArray[r1+1][i] == 0 ){if( yiZhe(r2+1, c2+1, r1+1, i, newArray)){path.add(new Point(r1,i-1));return true;}}elsebreak;}// 向左水平遍历for (int i = c1 ; i > -1; i--) {if (newArray[r1+1][i] == 0  ) {if(yiZhe(r1+1, i, r2+1, c2+1, newArray)){path.add(new Point(r1,i-1));return true;}}else break;}return false;}}

还有一个要说一下就是上面第一张图的那种二折情况,如果这种二折情况处于数组的边界的话,在使用上面的二折算法判断就会因为数组的问题,永远不可能实现相连。解决的方法就是:把数组扩大,在整个的数组外边加上一层,也就是说原来4*4变成6*6。把所有除原来4*4之外的位置的值都设为0,这样就能够遍历到了。不过在判断的时候要注意使用的是新数组的坐标还是旧数组的坐标(把新数组的坐标行下标和列下标都减一就是旧数组的行下标和列下标)。能够消除就意味着你的连连看游戏已经可以玩了,剩下的就是一些优化的问题了。

排行榜和存档功能的实现:这两个功能放一起讲,因为都用到了Java的IO的一些知识。这里主要用到的是Java中的FileOutputStream和FileInputStream这两个类。FileOutputStream这个类是把内存中的数据输出到外部的存储设备,主要的方法就是write(向目标文件一次写入一个字节)和close(关闭输出流);FileInputStream则是把外部的数据输入到内存中供程序使用,主要的方法就是read(从目标文件一次读取一个字节)和close(关闭输入流)。存档的思路就是:把当前的数组情况和时间记录下来(使用一个类来保存这两个信息),保存到一个文件中,下次打开游戏的时候询问用户是否载入进度。排行榜的话是如果玩家获胜,就记录下玩家的姓名和通关用时(同样使用一个类),保存到文件中。下面是代码,把存档和排行榜的相关类都放进去了:

package com.cbs.look;/*** 存档* * @author CBS*/public class CunD {private int array[][];private int time;public CunD() {}public CunD(int[][] array, int time) {this.array = array;this.time = time;}public int[][] getArray() {return array;}public void setArray(int[][] array) {this.array = array;}public int getTime() {return time;}public void setTime(int time) {this.time = time;}}
package com.cbs.look;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;/*** 用于保存游戏存档的信息* * @author CBS*/
public class GameSave2 {public boolean save(CunD d) {String path = "src/com/cbs/look/info.txt";try {OutputStream os = new FileOutputStream(path);os.write(d.getTime());for (int r = 0; r < d.getArray().length; r++) {for (int c = 0; c < d.getArray()[0].length; c++) {os.write(d.getArray()[r][c]);}}os.close();return true;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return false;}public CunD opean() {String path = "src/com/cbs/look/info.txt";try {InputStream is = new FileInputStream(path);int time = is.read();int array[][]=new int[8][8];for (int i = 0; i < array.length; i++)for (int j = 0; j < array[0].length; j++)array[i][j] = is.read();CunD c=new CunD(array,time);is.close();return c;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}
}
package com.cbs.look;/*** 记录排行榜的用户信息的类* * @author CBS* */
public class User {private String name;//用户名private int time;//记录用户通过所用时间public User() {}public User(String name, int time) {this.name = name;this.time = time;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getTime() {return time;}public void setTime(int time) {this.time = time;}@Overridepublic String toString() {String str=name+"用时为:"+time;return str;}}
package com.cbs.look;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;/*** 用于保存游戏排行榜信息* * @author CBS*/
public class GameSave {public boolean save(User user) {String path = "src/com/cbs/look/save3.txt";try {List<User> array = opean();if(array!=null){array.add(user);for (int i=0;i<array.size()-1;i++) {int flag=i;for(int j=i+1;j<array.size();j++){if(array.get(i).getTime()>array.get(j).getTime())flag=j;}if(flag!=i){User u1=array.get(i);User u2=array.get(flag);array.set(i, u2);array.set(flag, u1);}}}else{array=new ArrayList<User>(); array.add(user);}OutputStream os = new FileOutputStream(path);DataOutputStream dos=new DataOutputStream(os);//先写入有几条信息os.write(array.size());for (int i = 0; i < array.size(); i++) {User u =  array.get(i);dos.writeByte(u.getName().getBytes().length);dos.write(u.getName().getBytes());dos.writeInt(u.getTime());}os.close();dos.close();return true;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return false;}public List<User> opean() {String path = "src/com/cbs/look/save3.txt";try {InputStream is = new FileInputStream(path);DataInputStream dis = new DataInputStream(is); //读取有几条信息int size=is.read();List<User> list=new ArrayList<User>();if(size!=-1){for(int i=0;i<size;i++){byte bsize=dis.readByte();byte[] b=new byte[bsize];is.read(b);int time=dis.readInt();User u=new User(new String(b),time);list.add(u);}}dis.close();is.close();return list;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}
}

倒计时的实现:倒计时其实很简单使用一个线程就好(如果线程不了解请自行百度或者学习,不用很了解,知道就行,只是为了做个倒计时罢了),每次线程休眠一秒就让时间减一,然后把时间在窗体中输出就行了。也没什么可说的,上代码咯:

package com.cbs.look;
/*** 线程类,控制时间*/
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;public class TimeOut extends Thread {private int seconds=90;//游戏时间private JFrame frame;//主窗体对象private JLabel jl;//倒计时标签private boolean flag = true;// 控制线程结束private GameListener gl;//事件处理类// 在别的类中控制线程的关闭public void setFlag(boolean flag) {this.flag = flag;}public boolean isFlag() {return flag;}public int getSeconds() {return seconds;}public void setSeconds(int seconds) {this.seconds = seconds;}public TimeOut(JLabel jl, JFrame frame, GameListener gl) {this.jl = jl;this.frame = frame;this.gl = gl;}@Overridepublic void run() {//        seconds = 90;jl.setText(seconds + "");while (seconds-- > 0 && flag) {jl.setText(seconds + "");if (seconds == 0) {JOptionPane.showMessageDialog(frame, "不好意思,时间用光了,请开始新游戏");frame.removeMouseListener(gl);}try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

这样所有的东西也就都讲完了,剩下的就是如何把它们组织在一起形成你的东西了。

github:MissingBread/game

有需自取

java中showconfirmdialog_Java小游戏之连连看相关推荐

  1. 不愧是大厂牛人!用Java实现象棋小游戏(附超详细,超长究极无敌代码)

    本文实例为大家分享了java实现象棋小游戏的具体代码,供大家参考,具体内容如下 用Eclipse编写 java环境1.8jdk 代码如下 package xiangqi象棋; /***中国象棋Java ...

  2. Java练手小游戏---黄金矿工

    你玩过4399曾经最火的黄金矿工小游戏吗,黄金矿工小游戏是一款休闲娱乐的一个挖宝游戏,在游戏中地下会有许多的宝藏,你得想办法把它们都挖出来,作为矿工的你,对你来说是轻车熟路的,能不能挖到宝,看你抓取的 ...

  3. JAVA实现2048小游戏

    2048小游戏也算是一款好玩的益智休闲小游戏,下面本博主用 java 语言将该游戏复现,感兴趣的小伙伴点击 关注 哦! 同时博主还用 python 语言复现了该游戏,可点击以下链接浏览博主的另一篇文章 ...

  4. Java 贪吃虫小游戏

    我参考了[Java]Java实现贪吃蛇小游戏(带详细注释)和 java贪吃蛇小游戏(详解) 先设置需要用到的常数 package Snake;public class ConstantNumber { ...

  5. Java Swing 经典小游戏《飞机大战》———— (四)碰撞检测 游戏状态与得分 玩家升级

    前期回顾 Java Swing 经典小游戏<飞机大战>---- (一)获取素材,创建窗口,添加滚动背景,双缓冲 Java Swing 经典小游戏<飞机大战>---- (二)玩家 ...

  6. 手把手教你做一个Java贪吃蛇小游戏

    大家好,我是孙不坚1208,这篇博客给大家分享一下:如何做一个贪吃蛇小游戏(Java版)的exe应用程序,希望能给需要帮助的朋友带来方便. 手把手教你做一个Java贪吃蛇小游戏的exe应用程序 一.J ...

  7. Java实现五子棋小游戏(附源码)

    今天给大家分享一个用java写的小游戏--<五子棋> (完整代码可在[资源下载]目录查看) . 推荐学习专栏: Java基础学习专栏:[Java]基础篇 Java进阶学习专栏:[Java] ...

  8. Java黄金矿工小游戏,适合新手入门练手项目

    Java初学者的小伙伴们,相信大家肯定缺少很多的练手项目吧!今天就给大家推荐一款特别好上手的一个Java小游戏--黄金矿工. 大家听到这个名字的时候,童年的回忆肯定一下子,涌上心头,那如果让大家制作一 ...

  9. Java黄金矿工小游戏,适合初学者练手项目_java游戏_java项目

    黄金矿工小游戏是一款非常经典的休闲类挖宝游戏!相信绝大多数人小时候应该都玩过.但是你会玩游戏,你会做游戏吗(狗头)?对!你没猜错!我今天就是来给大家说怎么用Java做游戏的,希望看完之后你也会做哦~ ...

最新文章

  1. 浅析C#发送短信的原理
  2. 5.1.2 SELECT+INNER JOIN读取数据
  3. linux下的C语言开发(自动编译工具和config.h文件生成)
  4. MySQL(用户管理,常用sql语句,数据库备份恢复,MySQL调优,恢复误操作数据)...
  5. 黑马程序员-JavaSE核心知识-01Java介绍
  6. PHP 5.4 内置 web 服务器
  7. 阻滞增长模型求解_马尔萨斯与阻滞增长模型对于人口预测的分析
  8. 智象运维干货 | HP iLo4 Smash CLP命令行参考
  9. EPLAN教程——工具栏详解(1)自定义工具栏
  10. PD4ML将HTML文件转换成PDF文件
  11. 程序猿生存指南-33 寂寞撩人
  12. 又是一年新来到,别墅翻新要趁早
  13. 共享服务器文件溢出,文件共享软件Samaba中发现缓冲区溢出漏洞
  14. matlab 生成 gif
  15. 你不知道的Word中制作表格的7个技巧
  16. processon画类图和时序图
  17. Flink框架吐血总结,学习与面试收藏这一篇就够了,大数据必备知识体系
  18. 目前主流的app开发方式
  19. moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解
  20. AI 作画领域中的“神笔马良”是怎样炼成的?

热门文章

  1. FPGA与ASIC:它们之间的区别以及使用哪一种?
  2. 提示和技巧:光线跟踪最佳实践
  3. Kotlin for 循环使用
  4. android.view.InflateException: Binary XML file line #8: Binary XML file line #8: Error inflating cl
  5. Eclipse配置注释模板
  6. django系列 1 :python+django环境搭建 +mac提示找不到manage.py命令
  7. IIC通信控制的AD5259------在调试过程中遇到的奇葩问题
  8. 《windows核心编程系列》二谈谈ANSI和Unicode字符集
  9. Linux LVM逻辑卷配置过程详解
  10. java中数组的复制