
| 题目: | 连连看 |
| 姓名: | 曲一鸣 |
| 学号: | 1006840228 |
| 起止时间: | 2012.3.19-2012.4.17 |
| 自评成绩: | 优秀 |
| 理由: | 实现了连连看游戏的基本功能,增添了暂停,重置,提示,消除等附加功能。时间条和消除效果的动画表示。 |
连连看游戏经验,玩法简单,休闲,益智,趣味,广受欢迎。
【选题目的】:
学会JAVA程序开发的环境搭建与配置,并在实际运用中学习和掌握JAVA程序开发的全过程。进一步熟悉掌握JAVA程序设计语音的基础内容,如用户图形界面设计、JAVA多线程编程、JAVA数据库编程等。通过亲自动手写程序,拓展知识面,锻炼调试能力。
【系统分析与设计】:
功能分析:实现连连看的基本游戏功能和重置、提示、消除功能
设计:通过对图片的调用以及设置是否可见来完成连连看的效果
【课程设计中碰到的问题及解决方案】:
1.不知道如何进行对数组中两个元素是否可以消除的判断
2.时间条的动态表现
解决方案:
1.对每个相同图案进行循环判断,直到找出满足条件的情况
boolean verticalMatch(Point a, Point b) // 竖线上的判断
boolean horizonMatch(Point a, Point b) // 横线上的判断
2.为了保证动画过程和游戏过程的平行运行,因此将动画分离成一个的控件,并且要保证动画有自己单独的线程来运行。当每次用户的分数发生变化时,我们可以使用 setScore(int l, int c) 方法同步分数显示的动画效果。
【程序输出结果】:
游戏开始
提示功能
消除功能
游戏结束
关于
【总结自己的体会和收获】:
通过这次课程设计我学到了不少东西,也发现了大量的问题,同时在设计的过程中也发现了自己的不足之处,对以前学过的知识理解的不够深刻。对JAVA运用图片的调用和设置是否可见有了新的了解。但在部分功能的实现上还是有所不足,老师和同学都给予了很多帮助。让我懂得了JAVA的重要性和如何应用到实践后上。
【程序代码另附】:
ImageFactory
package nicholas.game.kyodai;
import javax.swing.ImageIcon;
import java.net.*;
public class ImageFactory {
private static ImageFactory imagefactory;
private static ImageIcon images[];
private ImageFactory() {
images = new ImageIcon[54];
URLClassLoader loader = (URLClassLoader)getClass().getClassLoader();
for(int i=0;i<39;i++) {
}
images
}
public ImageIcon getImageicon(int i) {
return images[i];
}
public static synchronized ImageFactory getInstance() {
if(imagefactory != null) {
return imagefactory;
} else {
imagefactory = new ImageFactory();
return imagefactory;
}
}
}
KyodaiGrid
package nicholas.game.kyodai;
import java.awt.*;
import javax.swing.*;
public class KyodaiGrid extends JLabel {
private int xpos;
private int ypos;
public KyodaiGrid(int x, int y) {
xpos = x;
ypos = y;
this.setHorizontalAlignment(SwingConstants.CENTER);
}
public int getXpos() {
return xpos;
}
public int getYpos() {
return ypos;
}
public boolean isPassable() {
return !isVisible();
}
}
LevelInfo
package nicholas.game.kyodai;
import java.io.Serializable;
public class LevelInfo implements Serializable {//xBound为行号,yBound为列号
private int xBound;
private int yBound;
public LevelInfo() {
xBound = 16;
yBound = 9;
}
public LevelInfo(int x, int y){
xBound = x;
yBound = y;
}
public int getXBound() {
return xBound;
}
public int getYBound() {
return yBound;
}
}
MainFrame.java
package nicholas.game.kyodai;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import nicholas.swing.AboutDialog;
import nicholas.swing.JSplashWindow;
public class MainFrame extends JFrame implements ActionListener {
private JMenuItem aboutItem;//菜单栏
private JMenuItem exitItem;
private JMenuItem startItem;
private JMenuItem optionItem;
private JMenuItem tipItem;
private JMenuItem refreshItem;
private JMenuItem logItem;
private JMenuItem bombItem;
private JMenuItem pauseItem;
private MainPanel mainPanel;//完成主要功能
private LevelInfo levelInfo;
public MainFrame() {
super("连连看");
levelInfo = new LevelInfo();//设定游戏大小
setMenuBar();//设置菜单
setUI();
setIconImage(ImageFactory.getInstance().getImageicon(43).getImage());
setSize(650,520);
Dimension screen = getToolkit().getScreenSize();
setLocation((screen.width-getSize().width)/2, (screen.height-getSize().height)/2);
this.setVisible(true);
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
}
private void setMenuBar() {
JMenu fileMenu = new JMenu("游戏(G)");
JMenu helpMenu = new JMenu("帮助(H)");
JMenu contMenu = new JMenu("辅助(C)");
fileMenu.setMnemonic('G');
helpMenu.setMnemonic('H');
contMenu.setMnemonic('C');
startItem = new JMenuItem("开局(N)");
startItem.setMnemonic('N');
startItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2,0));
pauseItem = new JMenuItem("暂停(P)");
pauseItem.setMnemonic('P');
pauseItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAUSE,0));
refreshItem = new JMenuItem("刷新(R)");
refreshItem.setMnemonic('R');
refreshItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3,0));
tipItem = new JMenuItem("提示(T)");
tipItem.setMnemonic('T');
tipItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5,0));
optionItem = new JMenuItem("选项(O)...");
optionItem.setMnemonic('O');
logItem = new JMenuItem("排行榜(B)...");
logItem.setMnemonic('B');
exitItem = new JMenuItem("退出(X)");
exitItem.setMnemonic('X');
aboutItem = new JMenuItem("关于(A)...");
aboutItem.setMnemonic('A');
aboutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1,0));
bombItem = new JMenuItem("(M)");
bombItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4,0));
bombItem.setMnemonic('M');
startItem.addActionListener(this);
pauseItem.addActionListener(this);
refreshItem.addActionListener(this);
tipItem.addActionListener(this);
optionItem.addActionListener(this);
logItem.addActionListener(this);
exitItem.addActionListener(this);
aboutItem.addActionListener(this);
bombItem.addActionListener(this);
fileMenu.add(startItem);
fileMenu.add(pauseItem);
contMenu.add(refreshItem);
contMenu.add(bombItem);
contMenu.add(tipItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
helpMenu.add(aboutItem);
helpMenu.add(contMenu);
JMenuBar bar = new JMenuBar();
bar.add(fileMenu);
bar.add(helpMenu);
setJMenuBar(bar);
}
private void setUI() {
mainPanel = new MainPanel(levelInfo);
getContentPane().add(mainPanel,BorderLayout.CENTER);
}
public static void main(String args[]) {
MainFrame application = new MainFrame();
}
private void showAboutDialog() {
String s1="作者: 曲一鸣";
String s2="邮箱: ****************";
String s3="Have Fun!!";
TextArea ta=new TextArea();
ta.setText(s1+"\\n"+"\\n"+"\\n"+s2+"\\n"+"\\n"+"\\n"+s3);
ta.setEditable(false);
JFrame f=new JFrame("关于");
f.setLocation(300, 300);
f.setSize(200,200);
f.add(ta);
f.setBackground(new Color(200,120,150));
f.setResizable(false);
f.setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
if(ae.getSource()==startItem) {
mainPanel.restart();
} else if(ae.getSource()==pauseItem) {
mainPanel.setPaused(!mainPanel.isPaused());
} else if(ae.getSource()==exitItem) {
System.exit(0);
} else if(ae.getSource()==aboutItem) {
showAboutDialog();
} else if(ae.getSource()==bombItem) {
mainPanel.useBomb();
} else if(ae.getSource()==refreshItem) {
mainPanel.refresh();
} else if(ae.getSource()==tipItem) {
mainPanel.showNext();
}
}
}
MainPanel.java
package nicholas.game.kyodai;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.border.Border;
import nicholas.game.kyodai.*;
public class MainPanel extends JPanel {
private int BOMB = 5;
private int BOMBP = 200;
private int REFRESH = 4;
private int REFRP = 250;
private int TIP = 7;
private int TIPP = 120;
private int PROGRESS = 1200;
private int xBound;
private int yBound;
private int pcount;
private int score;
private int refreshcount;
private int bombcount;
private int tipcount;
private LevelInfo levelInfo;
private GridMouseAdapter gma;
private KyodaiGrid grid[][];
private KyodaiGrid nexts, nexte;
private Border selectedBorder;
private Border opaqueBorder;
private Border tipBorder;
private Vector path[];
private Thread pthread;
private JProgressBar progress;
private JLabel scoreLabel;
private JLabel refreshLabel;
private JLabel bombLabel;
private JLabel tipLabel;
private JPanel gridPanel;
private boolean wingame;
public MainPanel(LevelInfo li) {
super(new BorderLayout());
levelInfo = li;
path = new Vector[3];
path[0] = new Vector();
path[1] = new Vector();
path[2] = new Vector();
setBackground(Color.black);
gma = new GridMouseAdapter();
opaqueBorder = BorderFactory.createLineBorder(getBackground());
//selectedBorder = BorderFactory.createLineBorder(Color.red);
selectedBorder = BorderFactory.createLineBorder(Color.red);
tipBorder = BorderFactory.createLineBorder(Color.green);
setGridPanel();
setStatusPanel();
}
/**
*设置状态面板
*/
private void setStatusPanel() {
wingame = false;
JPanel panel = new JPanel();
panel.setBackground(Color.black);
JLabel label = new JLabel("剩余时间:");
label.setForeground(Color.white);
panel.add(label);
progress = new JProgressBar(0,PROGRESS);//时间条显示
progress.setValue(PROGRESS);
progress.setPreferredSize(new Dimension(400,20));
progress.setForeground(Color.blue);
progress.setBorderPainted(false);
panel.add(progress);
score = 0;
scoreLabel = new JLabel(""+score);
scoreLabel.setForeground(Color.yellow);
scoreLabel.setFont(new Font("Dialog",Font.BOLD,25));
scoreLabel.setHorizontalAlignment(SwingConstants.RIGHT);
scoreLabel.setPreferredSize(new Dimension(100,20));
panel.add(scoreLabel);
add(panel,BorderLayout.NORTH);
panel = new JPanel();
panel.setBackground(Color.black);
label = new JLabel("剩余提示:");
label.setForeground(Color.yellow);
panel.add(label);
tipcount = TIP;
tipLabel = new JLabel(""+tipcount);
tipLabel.setForeground(Color.green);
panel.add(tipLabel);
label = new JLabel("剩余:");
label.setForeground(Color.yellow);
panel.add(label);
bombcount = BOMB;
bombLabel = new JLabel(""+bombcount);
bombLabel.setForeground(Color.green);
panel.add(bombLabel);
label = new JLabel("可用刷新:");
label.setForeground(Color.yellow);
panel.add(label);
refreshcount = REFRESH;
refreshLabel = new JLabel(""+refreshcount);
refreshLabel.setForeground(Color.green);
panel.add(refreshLabel);
add(panel,BorderLayout.SOUTH);
pthread = new ProgressThread();
pthread.start();
}
private void setGridPanel() {//完成布局
gridPanel = new JPanel();
gridPanel.setBackground(getBackground());
xBound = levelInfo.getXBound()+2;
yBound = levelInfo.getYBound()+2;
gridPanel.setLayout(new GridLayout(yBound,xBound,0,0));
grid = new KyodaiGrid[yBound][xBound];
int count = 0;
int sub = levelInfo.getXBound()*levelInfo.getYBound()/4;
KyodaiGrid temp[] = new KyodaiGrid[xBound*yBound];
for(int y=0;y if(x==0||x==(xBound-1)||y==0||y==(yBound-1)) { grid[y][x].setIcon(ImageFactory.getInstance().getImageicon(39)); grid[y][x].setVisible(false); } else { grid[y][x].setIcon(ImageFactory.getInstance().getImageicon(count%sub)); grid[y][x].setBorder(opaqueBorder); grid[y][x].addMouseListener(gma); temp[count] = grid[y][x]; count++; } gridPanel.add(grid[y][x]); } } JPanel t = new JPanel(); t.setBackground(Color.black); t.add(gridPanel); add(t,BorderLayout.CENTER); shuffle(temp, count); } /** *开始新游戏 */ public void restart() {//重新开始 resetStatusPanel(); resetGridPanel(); } /** *重置面板状态和游戏图标 */ private void resetStatusPanel() { wingame = false; score = 0; scoreLabel.setText(""+score); bombcount = BOMB; bombLabel.setText(""+bombcount); refreshcount = REFRESH; refreshLabel.setText(""+refreshcount); tipcount = TIP; tipLabel.setText(""+tipcount); progress.setValue(PROGRESS); pthread.resume(); } private void resetGridPanel() { int count = 0; int sub = (xBound-2)*(yBound-2)/4; KyodaiGrid temp[] = new KyodaiGrid[xBound*yBound]; for(int y=1;y grid[y][x].setBorder(opaqueBorder); grid[y][x].setVisible(true); temp[count] =grid[y][x]; count++; } } shuffle(temp,count); } /** *暂停 */ public void setPaused(boolean p) { if(p) { pthread.suspend(); gridPanel.setVisible(false); } else { pthread.resume(); gridPanel.setVisible(true); } } /** *是否暂停 */ public boolean isPaused() { return !gridPanel.isVisible(); } /** *没有布局存在时胜利 *计算得分 */ private void win() { wingame = true; pthread.suspend(); score += progress.getValue()/20+bombcount*BOMBP+refreshcount*REFRP+tipcount*TIPP; scoreLabel.setText(""+score); } private void shuffle(KyodaiGrid array[], int count) { if(wingame) return; do { setVisible(false); int j,k; Icon temp; for(int i=0;i k = (int)(Math.random()*count); temp = array[k].getIcon(); array[k].setIcon(array[j].getIcon()); array[j].setIcon(temp); } setVisible(true); } while(!findPair()); } public void refresh() { if(wingame||progress.getValue()==0||refreshcount==0) return; KyodaiGrid temp[] = new KyodaiGrid[xBound*yBound]; int count = 0; for(int y=1;y grid[y][x].setBorder(opaqueBorder); temp[count] = grid[y][x]; count++; } } } if(count!=0) { refreshcount--; refreshLabel.setText(""+refreshcount); shuffle(temp,count); } else win(); } private boolean xdirect(KyodaiGrid start, KyodaiGrid end,Vector path) { if(start.getYpos()!=end.getYpos()) return false; int direct = 1; if(start.getXpos()>end.getXpos()) { direct = -1; } path.removeAllElements(); for(int x=start.getXpos()+direct;x!=end.getXpos()&&x if(grid[start.getYpos()][x].isVisible()) return false; path.add(grid[start.getYpos()][x]); } path.add(end); return true; } private boolean ydirect(KyodaiGrid start, KyodaiGrid end,Vector path) { if(start.getXpos()!=end.getXpos()) return false; int direct = 1; if(start.getYpos()>end.getYpos()) { direct = -1; } path.removeAllElements(); for(int y=start.getYpos()+direct;y!=end.getYpos()&&y if(grid[y][start.getXpos()].isVisible()) return false; path.add(grid[y][start.getXpos()]); } path.add(end); return true; } private int findPath(KyodaiGrid start, KyodaiGrid end) { //0 conner if(xdirect(start,end,path[0])) { return 1; } if(ydirect(start,end,path[0])) { return 1; } //1 conner KyodaiGrid xy = grid[start.getYpos()][end.getXpos()]; if(!xy.isVisible()&&xdirect(start,xy,path[0])&&ydirect(xy,end,path[1])) { return 2; } KyodaiGrid yx = grid[end.getYpos()][start.getXpos()]; if(!yx.isVisible()&&ydirect(start,yx,path[0])&&xdirect(yx,end,path[1])) { return 2; } //2 conner //up path[0].removeAllElements(); for(int y=start.getYpos()-1;y>=0;y--) { xy = grid[y][start.getXpos()]; yx = grid[y][end.getXpos()]; if(xy.isVisible()) break; path[0].add(xy); if(!yx.isVisible()&&xdirect(xy,yx,path[1])&&ydirect(yx,end,path[2])) { return 3; } } //down path[0].removeAllElements(); for(int y=start.getYpos()+1;y yx = grid[y][end.getXpos()]; if(xy.isVisible()) break; path[0].add(xy); if(!yx.isVisible()&&xdirect(xy,yx,path[1])&&ydirect(yx,end,path[2])) { return 3; } } //left path[0].removeAllElements(); for(int x=start.getXpos()-1;x>=0;x--) { yx = grid[start.getYpos()][x]; xy = grid[end.getYpos()][x]; if(yx.isVisible()) break; path[0].add(yx); if(!xy.isVisible()&&ydirect(yx,xy,path[1])&&xdirect(xy,end,path[2])) { return 3; } } //right path[0].removeAllElements(); for(int x=start.getXpos()+1;x xy = grid[end.getYpos()][x]; if(yx.isVisible()) break; path[0].add(yx); if(!xy.isVisible()&&ydirect(yx,xy,path[1])&&xdirect(xy,end,path[2])) { return 3; } } return 0; } /** *在布局中消除配对 */ private void deletePair(KyodaiGrid prev, KyodaiGrid current) { //尝试寻找路径 //如果找到路径 //animate Vector temp = new Vector(); temp.add(prev); for(int i=0;i path[i].removeAllElements(); } AnimateThread thread = new AnimateThread(temp); thread.start(); score += progress.getValue()/20; scoreLabel.setText(""+score); progress.setValue(progress.getValue()+60); } /** *展示找到的配对 */ public void showNext() { if(wingame||progress.getValue()==0||tipcount==0) return; tipcount--; tipLabel.setText(""+tipcount); if(nexts!=null&&nexte!=null) { nexts.setBorder(tipBorder); nexte.setBorder(tipBorder); } } /** *删除找到的配对 */ public void useBomb() { if(wingame||progress.getValue()==0||bombcount==0) return; bombcount--; bombLabel.setText(""+bombcount); if(nexts!=null&&nexte!=null) { deletePair(nexts,nexte); } } /** *发现有连接路径的配对 *@返回是否发现 */ private boolean findPair() { nexts = null; nexte = null; for(int sy=1;sy for(int ey=sy;ey if(grid[sy][sx].getIcon()==grid[ey][ex].getIcon()) { pcount = findPath(grid[sy][sx],grid[ey][ex]); if(pcount!=0) { nexts = grid[sy][sx]; nexte = grid[ey][ex]; return true; } } } } } } return false; } private class GridMouseAdapter extends MouseAdapter { private KyodaiGrid prev; public void mouseClicked(MouseEvent me) { if(prev == null) { prev = (KyodaiGrid)me.getSource(); prev.setBorder(selectedBorder); } else { if(progress.getValue()==0) return; KyodaiGrid current = (KyodaiGrid)me.getSource(); if(current == prev) return; if(current.getIcon()==prev.getIcon()) { pcount = findPath(prev,current); if(pcount!=0) { deletePair(prev,current); //set prev = null; return; } } prev.setBorder(opaqueBorder); prev = current; prev.setBorder(selectedBorder); if(!findPair()) refresh(); } } } private class AnimateThread extends Thread { private Vector v; public AnimateThread(Vector temp) { v = temp; } public void run() { KyodaiGrid prev = null; KyodaiGrid current; int j = 0; while(j prev.setVisible(true); v.add(prev); j++; try { sleep(20); } catch(InterruptedException ire) { System.err.println("sleep interrupted"); } } current = prev; prev = (KyodaiGrid)v.remove(0); while(!v.isEmpty()) { ((KyodaiGrid)v.remove(0)).setVisible(false); try { sleep(20); } catch(InterruptedException ire) { System.err.println("sleep interrupted"); } } prev.setVisible(false); current.setVisible(false); current.setIcon(ImageFactory.getInstance().getImageicon(39)); prev.setIcon(ImageFactory.getInstance().getImageicon(39)); current.setBorder(opaqueBorder); prev.setBorder(opaqueBorder); if(!findPair()) refresh(); }//end of method run } private class ProgressThread extends Thread { public ProgressThread() {} public void run() { while(true) { while(progress.getValue()>0) { progress.setValue(progress.getValue()-1); try { sleep(100); } catch(InterruptedException ire) { System.err.println("sleep interrupted"); } } repaint(); suspend(); } } } }
