说明:本篇博客主要讲述练练看游戏的设计与实现。前半部分为分析与类和属性的说明,后半部分为程序的实现与程序代码。第一次写小游戏,仍存在许多问题,也借鉴了CSDN前辈的代码想法,如有不妥,还望多批评指正。
主界面显示类MainShow和游戏显示类GameShow继承窗口类JFrame,主界面显示类MainShow通过监听器类Listener创建游戏显示类GameShow;游戏显示类GameShow主要由三个面板类进行显示,其中上面板UpPanel和下面板DownPanel用来显示玩家和游戏信息,中面板CenterPanel用来显示连连看游戏;时间类Time继承Timer类,来完成对时间的监控。
玩家在主界面显示类MainShow通过Play按钮调用监听器类Listener打开游戏界面GameShow,控制类Control通过函数控制界面的显示。具体的类图如下:
图1 类图实现
可以根据图3显示的类进行查看各个类的属性,其详细属性说明如下:
属性:
private JButton Play:用于点击链接游戏主界面。
private JButton More:用于点击链接显示更多信息。
private ImageIcon imgPlay:显示Play的图片。
private ImageIcon imgMore:显示More的图片。
private ImageIcon backGroundImg: 显示主界面的背景图片。
private int IMGH:表示背景图片的高。
private int IMGW:表示背景图片的宽。
private JLabel label:标签背景图片内容。
private JPanel panel:面板显示内容。
private ActionListener Listener:监听器用于对操作进行监听。
函数方法:
public MainShow():重载函数。
public MainShow(int i):重载函数。
public void buttonCreated():用于创建的按钮的函数。
public void actionPerformed(ActionEvent e):监听器函数。
说明:主界面MainShow主要用于显示游戏的主登录选择界面,方便玩家登录、开始游戏和查看更多信息等操作。
属性:
private JFrame mainFrame:用于显示游戏的主界面。
private int bimgh, bimgw:用于显示游戏背景的宽和高。
public static int COLS = 10:设置练练看游戏棋盘的列数。
public static int ROWS = 5:设置练练看游戏期盼的行数。
private JPanel mainpanel:设置游戏的主面板
private JPanel centerPanel:设置游戏主面板中的中间面板。
private JPanel upPanel:设置游戏主面板中的上面板,用于显示游戏信息。
private JPanel downPanel:设置游戏主面板中的下面板,用于显示游戏信息。
private ImageIcon backImg,:设置游戏的背景图片。
private ImageIcon img:显示的练练看游戏图片。
private ImageIcon tsimg:显示的提示按钮图片。
private ImageIcon cpimg:显示的重排按钮图片。
private ImageIcon fsimg0, fsimg1, fsimg2, fsimg3:显示分数图片。
private ImageIcon levelImg:显示玩家的等级图片。
private Chess aniButton[][] = new Chess[COLS][ROWS]:棋盘的二维数组。
private JButton exitButton:显示游戏的退出按钮。
private JButton cpButton:显示游戏的重排按钮。
private JButton sxButton:显示游戏的刷新按钮。
private Chess firstChess:表示点击的点击第一个按钮棋子。
private Chess secondChess:表示点击的点击第二个按钮棋子
private JLabel score = new JLabel("0"):用标签表示玩家的分数。
private JLabel label:用来显示标签。
private JLabel tsfs:显示提示次数的分数。
private JLabel cpfs:显示重排次数的分数。
private JLabel level:用于表示玩家等级的标签
private int grid[][] = new int[COLS + 2][ROWS + 2]:用于代替显示棋子位置。
static boolean pressInformation = false:表示事件的正确失败。
private int x0 = 0, y0 = 0, x = 0, y = 0,fristMsg = 0, secondMsg = 0:
private int i, j, k, n:代替变量显示。
private int imgh, imgw:显示图片的高和宽度。
private JProgressBar progressBar = new JProgressBar():表示一个进度条。
private Timer timer:表示一个时间类。
private int value:表示时间的值。
函数方法:
public GameShow():重载函数。
public void actionPerformed(ActionEvent e):监听器函数,对相应操作调用函数,利用控制类中的函数进行调用显示。
public void time():时间函数,用于创建timer进程与及时。
public void ChessPrint():用于绘制棋子的显示。
属性:
属性大多数都引入的是GameShow中的属性或者为替代属性,不做多余论述。
方法函数:
public void cpBuild():对重排按钮的响应,用于对死局的棋子进行重排。
public void sxBuil():对刷新按钮的响应,用于对棋子进行刷新。
public void numberJudge():对重排、刷新等剩余次数的判断。
public void lineImg():用于连接图片的总函数。
public void linePassOne():连线经过一个拐点的函数。
public void linePassTwo():连线经过二个拐点的函数。
public void estimateEvent():用于判断是两个图片是否可以连接。
public void lineImg():用于连接图片的总函数。
public void sxBuil():对刷新按钮的响应,用于对棋子进行刷新。
public void remove():对棋子的消除操作。
public void sorceChange():对连连看分数的改变。
类似于迷宫求解问题所利用的,分类搜索算法的基本原理是一种递归思想。假设我们要判断A单元与B单元格是否可以通过一条具有N个拐点的路径相连,该问题可以转化为能否找到一个C单元格,C与A可以直线连接(0折连接),且C与B可以通过一条具有N-1个拐点的路径连接。根据分类搜索算法,可以将图片的连接分类转化为直接连接、一折连接、二折连接。通过递归来判断图片内容是否一致,图片所处位置是否可连接。在确定图片可以连接后,对图片进行消除函数进行处理,使Chess元素的显示为false。如图4 分类搜索算法图。
图2 分类搜索算法图
0折连接表示A与B的X坐标或Y坐标相等,可以直线连接,不需要任何拐点,且连通的路径上没有任何阻碍。
3 0折搜索模型图
1折连接与0折连接恰好相反,要求A单元格与B单元格的X轴坐标与Y轴坐标都不能相等。此时通过A与B可以画出一个矩形,而A与B位于矩形的对角点上。
图4 1折搜索模型图
判断A单元格与B单元格能否经过两个拐点连接,可以转化为判断能否找到一个C单元格,该C单元格可以与A单元格0折连接,且C与B可以1折连接。
图5 2折搜索模型图
1、主界面类
package lianliankan;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.sun.glass.events.WindowEvent;
/*
* 连连看首页界面
*/
public class MainShow extends JFrame {
private static final long serialVersionUID = 1L;
//首页背景图片 Play键More键
private ImageIcon img;
private ImageIcon imgPlay, imgMore;
//首页图片宽和高 和临时变量
private int IMGW, IMGH;
private int imgw, imgh;
//标签 布局 按钮等 监听器
private JLabel label;
private JPanel panel;
private JButton play, more, button;
private ActionListener playListener, moreListener;
//执行函数
public static void main(String[] args){
new MainShow();
}
//重载函数
public MainShow()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
img = new ImageIcon("src/images/bg01.png"); //背景图片
IMGH = img.getIconHeight(); //得到图片高
IMGW = img.getIconWidth(); //得到图片宽
this.setBounds(200,200,IMGW+10,IMGH+30);
this.setTitle("连连看");
label = new JLabel(img);
label.setBounds(0,0,IMGW,IMGH);
this.getLayeredPane().add(label,new Integer(Integer.MIN_VALUE));
this.setLayout(null);
panel = new JPanel();
panel.setLayout(null);
panel.setBounds(0,IMGH/2,IMGW,IMGH/2);
panel.setOpaque(false);
setContentPane(panel);
setVisible(true);
getContentPane().setLayout(null);
play = new JButton();
play.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
more = new JButton();
imgPlay = new ImageIcon("src/images/play.png");
imgMore = new ImageIcon("src/images/more.png");
play.setIcon(imgPlay);
more.setIcon(imgMore);
add(play);
add(more);
play.setBounds((IMGW/2)-102,(IMGH/2)+23,193,47);
play.setBorderPainted(false);
more.setBounds((IMGW/2)-102,(IMGH/2)+76,182,52);
more.setBorderPainted(false);
playListener = new PlayListener();
moreListener = new MoreListener();
play.addActionListener(playListener);
more.addActionListener(moreListener);
}
//重载函数
public MainShow(int i)
{
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
img=new ImageIcon("src/images/bg01.png");
IMGH=img.getIconHeight();
IMGW=img.getIconWidth();
this.setBounds(200, 200, IMGW, IMGH);
this.setTitle("连连看");
label = new JLabel(img);
label.setBounds(0,0,IMGW,IMGH);
this.getLayeredPane().add(label,new Integer(Integer.MIN_VALUE));
this.setLayout(null);
panel = new JPanel();
panel.setLayout(null);
panel.setBounds(IMGH/2,IMGH/2,IMGW,IMGH/2);
img = new ImageIcon("src/images/01.png");
imgw = img.getIconWidth() + 2;
imgh = img.getIconHeight() + 2;
for(int cols = 1;cols < 6;cols++)
{
for(int rows = 0;rows < 5;rows++ )
{
buttonCreated2("src/"+cols+".png",cols+"",cols*imgw,rows*imgh,imgw,imgh);
}
}
panel.setOpaque(false);
this.setContentPane(panel);
this.setVisible(true);
}
public void buttonCreated2(String file,String command,int x,int y,int w,int h)
{
img=new ImageIcon(file);
button=new JButton(img);
button.setBounds(x,y,imgw,imgh);
button.setContentAreaFilled(false);
button.setActionCommand(command);
panel.add(button);
}
public void actionPerformed(ActionEvent e){
this.dispose();
}
public void windowActivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowClosed(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowClosing(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowDeactivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowDeiconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowIconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
public void windowOpened(WindowEvent arg0) {
// TODO Auto-generated method stub
}
}
2、游戏显示类
package lianliankan;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.JProgressBar;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
class GameShow implements ActionListener, ChangeListener {
// 主窗口 窗口的大小
private JFrame mainFrame;
private int bimgh, bimgw;
// 设置棋盘的行与列
public static int COLS = 10;
public static int ROWS = 5;
// 定义主上中下三面板
private JPanel mainpanel, centerPanel, upPanel, downPanel;
private ImageIcon bimg, img, tsimg, cpimg, fsimg0, fsimg1, fsimg2, fsimg3, levelimg;
// 定义按钮
private JButton aniButton[][] = new JButton[COLS][ROWS];
private JButton exitButton, randButton, newlyButton;
private JButton firstButton, secondButton;
// 定义分数标签
private JLabel score = new JLabel("0");
private JLabel fraction, label, tsfs, cpfs, level;
// 自定义变量
private int grid[][] = new int[COLS + 2][ROWS + 2];
static boolean pressInformation = false;
private int x0 = 0, y0 = 0, x = 0, y = 0, fristMsg = 0, secondMsg = 0;
private int i, j, k, n;
private int imgh, imgw;
// 进度条 进度条计时器 初始值
private JProgressBar progressBar = new JProgressBar();
private Timer timer;
private int value;
// 主显示函数
public void init() {
chessPrint();
buttonPrint();
time();
}
// 时间进度条设置函数
public void time() {
progressBar.setStringPainted(true);
JLabel timejl = new JLabel();
value = 60;
progressBar.setValue(value);
progressBar.setMaximum(value);
progressBar.setMinimum(0);
progressBar.setBounds(200, 12, 400, 20);
timejl.setBounds(140, 10, 60, 25);
timejl.setFont(new java.awt.Font("Dialog", 1, 20));
timejl.setText("Time:");
upPanel.add(progressBar);
upPanel.add(timejl);
}
// 显示连连看背景 棋子函数
public void chessPrint() {
// 设置背景图像 得到高和宽
bimg = new ImageIcon("src/images/bg02.png");
bimgh = bimg.getIconHeight();
bimgw = bimg.getIconWidth();
// 设置窗口名称 位置 显示大小
mainFrame = new JFrame("连连看");
mainFrame.setBounds(200, 200, bimgw + 10, bimgh + 30);
// 设置标签上显示背景图片 设置显示
label = new JLabel(bimg);
label.setBounds(0, 0, bimgw, bimgh);
mainFrame.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));
// 对任意一图片取值得到高和宽
img = new ImageIcon("src/images/1.jpg");
imgh = img.getIconHeight();
imgw = img.getIconWidth();
// 设置主面板添加内容 设置布局
mainpanel = new JPanel();
mainFrame.setContentPane(mainpanel);
mainpanel.setLayout(null);
mainpanel.setOpaque(false);
// 设置控件添加 设置透明
upPanel = new JPanel();
centerPanel = new JPanel();
downPanel = new JPanel();
upPanel.setBounds(0, 0, 642, 40);
centerPanel.setBounds(0, 60, 642, 400);
downPanel.setBounds(0, 400, 642, 70);
centerPanel.setOpaque(false);
upPanel.setOpaque(false);
downPanel.setOpaque(false);
mainFrame.add(downPanel);
mainFrame.add(upPanel);
mainFrame.add(centerPanel);
upPanel.setLayout(null);
centerPanel.setLayout(null);
downPanel.setLayout(null);
// 设置按钮图片棋子
for (int cols = 0; cols < COLS; cols++) {
for (int rows = 0; rows < ROWS; rows++) {
// 获取图片参数 产生随机图片
img = new ImageIcon("src/images/" + String.valueOf(grid[cols + 1][rows + 1]) + ".jpg");
img.setImage(img.getImage().getScaledInstance(imgw, imgh, Image.SCALE_DEFAULT));
// 设置按钮上图片 位置
aniButton[cols][rows] = new JButton(img);
aniButton[cols][rows].setBounds(bimgw / 2 - COLS * imgw / 2 + cols * imgw, rows * imgh, imgw, imgh);
// 按钮 手掌形鼠标 边界为空 透明显示
aniButton[cols][rows].setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
aniButton[cols][rows].setBorder(null);
aniButton[cols][rows].setContentAreaFilled(false);
aniButton[cols][rows].addActionListener(this);
centerPanel.add(aniButton[cols][rows]);
}
}
}
// 显示功能性按钮
public void buttonPrint() {
fsimg3 = new ImageIcon("src/images/tsfenshu3.png");
fsimg2 = new ImageIcon("src/images/tsfenshu2.png");
fsimg1 = new ImageIcon("src/images/tsfenshu1.png");
fsimg0 = new ImageIcon("src/images/tsfenshu0.png");
// 返回设置 设置透明 无边框 监听
exitButton = new JButton("BACK");
exitButton.addActionListener(this);
exitButton.setBounds(190, 10, 70, 40);
exitButton.setBackground(Color.green);
downPanel.add(exitButton);
// 重排设置 设置透明 无边框 监听
cpimg = new ImageIcon("src/images/chongpai.png");
cpfs = new JLabel(fsimg3);
randButton = new JButton(cpimg);
randButton.setContentAreaFilled(false);
randButton.addActionListener(this);
randButton.setBounds(300, 10, 46, 42);
cpfs.setBounds(350, 10, 58, 38);
downPanel.add(randButton);
downPanel.add(cpfs);
// 重开设置 透明 无边框 监听
tsimg = new ImageIcon("src/images/tishi.png");
tsfs = new JLabel(fsimg3);
newlyButton = new JButton(tsimg);
newlyButton.setContentAreaFilled(false);
newlyButton.addActionListener(this);
newlyButton.setBounds(450, 10, 46, 44);
tsfs.setBounds(500, 10, 58, 38);
downPanel.add(newlyButton);
downPanel.add(tsfs);
// 等级设置 后续修改
levelimg = new ImageIcon("src/images/level.png");
level = new JLabel(levelimg);
level.setBounds(20, 0, 124, 69);
downPanel.add(level);
// 分数设置 透明 无边框 监听
score.setText(String.valueOf(Integer.parseInt(score.getText())));
score.setFont(new java.awt.Font("Dialog", 1, 20));
img = new ImageIcon("src/images/fenshu.png");
fraction = new JLabel(img);
upPanel.add(fraction);
fraction.setBounds(10, 10, 48, 25);
upPanel.add(score);
score.setBounds(68, 10, 60, 25);
mainFrame.setVisible(true);
}
public void randomBuild() {
int randoms, cols, rows;
for (int twins = 1; twins <= COLS * ROWS / 2; twins++) {
randoms = (int) (Math.random() * 9 + 1);
for (int alike = 1; alike <= 2; alike++) {
cols = (int) (Math.random() * COLS + 1);
rows = (int) (Math.random() * ROWS + 1);
while (grid[cols][rows] != 0) {
cols = (int) (Math.random() * COLS + 1);
rows = (int) (Math.random() * ROWS + 1);
}
this.grid[cols][rows] = randoms;
}
}
}
public void fraction() {
score.setText(String.valueOf(Integer.parseInt(score.getText()) + 100));
}
public void reload() {
int save[] = new int[COLS * ROWS];
int n = 0, cols, rows;
int grid[][] = new int[COLS + 10][ROWS + 10];
for (int i = 0; i <= COLS; i++) {
for (int j = 0; j <= ROWS; j++) {
if (this.grid[i][j] != 0) {
save[n] = this.grid[i][j];
n++;
}
}
}
n = n - 1;
this.grid = grid;
while (n >= 0) {
cols = (int) (Math.random() * COLS + 1);
rows = (int) (Math.random() * ROWS + 1);
while (grid[cols][rows] != 0) {
cols = (int) (Math.random() * COLS + 1);
rows = (int) (Math.random() * COLS + 1);
}
this.grid[cols][rows] = save[n];
n--;
}
mainFrame.setVisible(false);
pressInformation = false;
init();
for (int i = 0; i < COLS; i++) {
for (int j = 0; j < ROWS; j++) {
if (grid[i + 1][j + 1] == 0)
aniButton[i][j].setVisible(false);
}
}
}
public void estimateEven(int placeX, int placeY, JButton bz) {
if (pressInformation == false) {
x = placeX;
y = placeY;
secondMsg = grid[x][y];
secondButton = bz;
pressInformation = true;
} else {
x0 = x;
y0 = y;
fristMsg = secondMsg;
firstButton = secondButton;
x = placeX;
y = placeY;
secondMsg = grid[x][y];
secondButton = bz;
if (fristMsg == secondMsg && secondButton != firstButton) {
linkImg();
}
}
}
public void linkImg() {
if ((x0 == x && (y0 == y + 1 || y0 == y - 1)) || ((x0 == x + 1 || x0 == x - 1) && (y0 == y))) {
remove();
} else {
for (j = 0; j < ROWS + 2; j++) {
if (grid[x0][j] == 0) {
if (y > j) {
for (i = y - 1; i >= j; i--) {
if (grid[x][i] != 0) {
k = 0;
break;
} else {
k = 1;
}
}
if (k == 1) {
linePassOne();
}
}
if (y < j) {
for (i = y + 1; i <= j; i++) {
if (grid[x][i] != 0) {
k = 0;
break;
} else {
k = 1;
}
}
if (k == 1) {
linePassOne();
}
}
if (y == j) {
linePassOne();
}
}
if (k == 2) {
if (x0 == x) {
remove();
}
if (x0 < x) {
for (n = x0; n <= x - 1; n++) {
if (grid[n][j] != 0) {
k = 0;
break;
}
if (grid[n][j] == 0 && n == x - 1) {
remove();
}
}
}
if (x0 > x) {
for (n = x0; n >= x + 1; n--) {
if (grid[n][j] != 0) {
k = 0;
break;
}
if (grid[n][j] == 0 && n == x + 1) {
remove();
}
}
}
}
}
for (i = 0; i < COLS + 2; i++) {
if (grid[i][y0] == 0) {
if (x > i) {
for (j = x - 1; j >= i; j--) {
if (grid[j][y] != 0) {
k = 0;
break;
} else {
k = 1;
}
}
if (k == 1) {
rowPassOne();
}
}
if (x < i) {
for (j = x + 1; j <= i; j++) {
if (grid[j][y] != 0) {
k = 0;
break;
} else {
k = 1;
}
}
if (k == 1) {
rowPassOne();
}
}
if (x == i) {
rowPassOne();
}
}
if (k == 2) {
if (y0 == y) {
remove();
}
if (y0 < y) {
for (n = y0; n <= y - 1; n++) {
if (grid[i][n] != 0) {
k = 0;
break;
}
if (grid[i][n] == 0 && n == y - 1) {
remove();
}
}
}
if (y0 > y) {
for (n = y0; n >= y + 1; n--) {
if (grid[i][n] != 0) {
k = 0;
break;
}
if (grid[i][n] == 0 && n == y + 1) {
remove();
}
}
}
}
}
}
}
public void linePassOne() {
if (y0 > j) {
for (i = y0 - 1; i >= j; i--) {
if (grid[x0][i] != 0) {
k = 0;
break;
} else {
k = 2;
}
}
}
if (y0 < j) {
for (i = y0 + 1; i <= j; i++) {
if (grid[x0][i] != 0) {
k = 0;
break;
} else {
k = 2;
}
}
}
}
public void rowPassOne() {
if (x0 > i) {
for (j = x0 - 1; j >= i; j--) {
if (grid[j][y0] != 0) {
k = 0;
break;
} else {
k = 2;
}
}
}
if (x0 < i) {
for (j = x0 + 1; j <= i; j++) {
if (grid[j][y0] != 0) {
k = 0;
break;
} else {
k = 2;
}
}
}
}
// 连线之后去除图片
public void remove() {
firstButton.setVisible(false);
secondButton.setVisible(false);
fraction();
pressInformation = false;
k = 0;
grid[x0][y0] = 0;
grid[x][y] = 0;
}
// 对点击 进度条的监听
public void stateChanged(ChangeEvent e) {}
int cpjudge = 3;
int tsjudge = 3;
public void actionPerformed(ActionEvent e) {
int value = progressBar.getValue();
if (value > 0) {
value--;
progressBar.setValue(value);
} else {
timer.stop();
progressBar.setValue(100);
}
if (e.getSource() == newlyButton) {
if (tsjudge > 0) {
int grid[][] = new int[COLS + 2][ROWS + 2];
this.grid = grid;
randomBuild();
mainFrame.setVisible(false);
pressInformation = false;
init();
tsjudge--;
judge();
cpjudge = 3;
}
}
if (e.getSource() == exitButton) {
new MainShow();
mainFrame.dispose();
}
if (e.getSource() == randButton)
if (cpjudge > 0) {
reload();
cpjudge--;
judge();
}
for (int cols = 0; cols < COLS; cols++) {
for (int rows = 0; rows < ROWS; rows++) {
if (e.getSource() == aniButton[cols][rows])
estimateEven(cols + 1, rows + 1, aniButton[cols][rows]);
}
}
}
public void judge(){
if(cpjudge == 3)
cpfs.setIcon(fsimg3);
if(cpjudge == 2)
cpfs.setIcon(fsimg2);
if(cpjudge == 1)
cpfs.setIcon(fsimg1);
if(cpjudge == 0)
cpfs.setIcon(fsimg0);
if(tsjudge == 3)
tsfs.setIcon(fsimg3);
if(tsjudge == 2)
tsfs.setIcon(fsimg2);
if(tsjudge == 1)
tsfs.setIcon(fsimg1);
if(tsjudge == 0)
tsfs.setIcon(fsimg0);
tsfs.setBounds(500, 10, 58, 38);
cpfs.setBounds(350, 10, 58, 38);
downPanel.add(cpfs);
downPanel.add(tsfs);
}
}
本代码还有一些bug,代码仅供参考!
图片链接: https://pan.baidu.com/s/1zexTKLsTzN5bQ_SSAsgQAg 提取码: 95wa