大家好,我是陈橘又青,今天用Java编程实现图形化界面的魔板游戏,以下是完整的开发思路以及代码,供各位讨论交流。
目录
1️⃣效果展示
①图像玩法
②数字玩法
③测试界面
2️⃣项目介绍
①项目背景
②功能分析
③设计要求
3️⃣代码展示
①图形界面设计(gui包)
主类:AppWindows类
②用户操作设计(data包)
Block类
HandleImage类
Point类
VerifySuccess类
③游戏视图设计(view包)
HandleMove类
PuzzlePad类
4️⃣代码测试
5️⃣项目结构
6️⃣设计总结
初级模式
高级模式
魔板游戏是一款益智游戏,该游戏有两种形式:一种是由若干个有序不等数字组成,而另一种是由图像组成。人们在将其恢复至最原始的序列而形成完整的排列时,会充分考验玩家的智商,是人们休闲娱乐时可供选择的消遣工具。
魔板游戏分为两个级别,用户可以根据自己的水平来选择“初级”或者“高级”,更具灵活性,并且更贴近用户的需求。对于“初级”级别,魔板由 3*3个格子组成,对于“高级”级别,魔板由 4*4 个格子组成。
该游戏需要实现以下几个功能:
(1) 用户以“数字”或“图像”的形式来玩魔板游戏。
(2) 用户可以根据个人需要来选择魔板游戏的级别:“初级”或者“高级”。
①魔板由3*3或4*4个格子组成。对于3*3魔板:在前八个格子里随机放置8个编号1~8的方块,最后一个格子是未放置方块的空格子,对于4*4的魔板:在前15个格子里随机放置15个编号为 1~15的方块,最后一个格子是未放置方块的空格子。
②用鼠标单击任何与空格子水平或垂直相邻的方块可以把该方块移入空格子,而当前方块移动之前所在的格子成为空格子。通过不断地移动方块可以将方块一行一行地按数字顺序排好。
③魔板游戏也可用图像来代替数字。如:对于3*3的魔板,将一幅图像分成3*3幅小图像,除去最后一幅小图像(图像的右下角)将其余各幅小图像打乱顺序放在魔板的方块上,最终目标是通过移动方块恢复原始图像(不包括图像的右下角)。
④当用户按要求排列好方块后,程序弹出对话框,提示用户成功的消息。
⑤魔板游戏分为两个级别:用户可以通过界面上提供的菜单来选择“初级”或者“高级”两个级别。
⑥“魔板游戏”提供一幅默认图像,用户可以使用该图像来玩魔板游戏。用户也可以使界面提供的菜单选择一幅新图像来玩该游戏。
AppWindow类负责创建游戏的主窗口,该类含有main方法,程序从该类开始执行。
package ch7.gui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.swing.filechooser.*;
import ch7.view.PuzzlePad;
public class AppWindow extends JFrame implements ActionListener{
PuzzlePad puzzlePad;
JMenuBar bar;
JMenu gradeMenu,choiceImage;
JMenuItem oneGrade,twoGrade,newImage,defaultImage;
JRadioButton digitPlay,imagePlay;
ButtonGroup group=null;
JButton startButton;
Image image;
Toolkit tool;
public AppWindow(){
tool=getToolkit();
bar=new JMenuBar();
gradeMenu=new JMenu("选择级别");
choiceImage=new JMenu("选择图像");
oneGrade=new JMenuItem("初级");
twoGrade=new JMenuItem("高级");
newImage=new JMenuItem("选择一幅新图像");
defaultImage=new JMenuItem("使用默认图像");
gradeMenu.add(oneGrade);
gradeMenu.add(twoGrade);
choiceImage.add(newImage);
choiceImage.add(defaultImage);
bar.add(gradeMenu);
bar.add(choiceImage);
setJMenuBar(bar);
oneGrade.addActionListener(this);
twoGrade.addActionListener(this);
newImage.addActionListener(this);
defaultImage.addActionListener(this);
startButton=new JButton("开始");
startButton.addActionListener(this);
group=new ButtonGroup();
digitPlay=new JRadioButton("数字玩法",true);
imagePlay=new JRadioButton("图像玩法",false);
group.add(digitPlay);
group.add(imagePlay);
puzzlePad=new PuzzlePad();
puzzlePad.setGrade(1);
puzzlePad.setIsDigitPlay();
add(puzzlePad,BorderLayout.CENTER);
JPanel pNorth=new JPanel();
pNorth.add(digitPlay);
pNorth.add(imagePlay);
pNorth.add(startButton);
pNorth.add(new JLabel("如果图像不能立刻显示,请再单击一次按扭"));
add(pNorth,BorderLayout.NORTH);
add(puzzlePad.getHandleMove(),BorderLayout.SOUTH);
validate();
setVisible(true);
setBounds(100,50,550,380);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try{
image=tool.createImage(new File("拼图图像/default.jpg").toURI().toURL());
puzzlePad.setImage(image);
}
catch(Exception exp){}
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==startButton){
if(digitPlay.isSelected()){
puzzlePad.setIsDigitPlay();
}
else if(imagePlay.isSelected()){
puzzlePad.setImage(image);
puzzlePad.setIsImagePlay();
}
}
else if(e.getSource()==oneGrade){
puzzlePad.setGrade(1);
}
else if(e.getSource()==twoGrade){
puzzlePad.setGrade(2);
}
else if(e.getSource()==newImage){
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"JPG & GIF Images", "jpg", "gif");
JFileChooser chooser=new JFileChooser();
chooser.setFileFilter(filter);
int state=chooser.showOpenDialog(null);
File file=chooser.getSelectedFile();
if(file!=null&&state==JFileChooser.APPROVE_OPTION){
try{
image=tool.createImage(file.toURI().toURL());
puzzlePad.setImage(image);
}
catch(Exception exp){}
}
}
else if(e.getSource()==defaultImage){
try{
image=tool.createImage(new File("拼图图像/default.jpg").toURI().toURL());
puzzlePad.setImage(image);
}
catch(Exception exp){}
}
}
public static void main(String args[]){
new AppWindow();
}
}
Block类是 JTextField的一个子类创建的对象是 PuzzlePad类的重要成员之一,用来表示“魔板”中的“方块”
package ch7.data;
import javax.swing.*;
import java.awt.*;
public class Block extends JTextField{
Point point; //方块所在点
Object object; //方块上的图像
Point [][] allPoint; //全部点位置
int index_i,index_j ; //点的索引
public Block(){
setEditable(false);
setHorizontalAlignment(JTextField.CENTER);
setFont(new Font("Arial",Font.BOLD,16));
setForeground(Color.blue);
}
public void setAtPoint(Point p){
point=p;
}
public void setAllPoint(Point [][] point){
allPoint = point;
}
public Point getAtPoint(){
return point;
}
public void setObject(Object object){
this.object=object;
if(object instanceof Integer){
Integer number=(Integer)object;
setText(""+number.intValue());
}
else if(object instanceof Image){
repaint();
}
}
public Object getObject(){
return object;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
int w=getBounds().width;
int h=getBounds().height;
try{
g.drawImage((Image)object,0,0,w,h,this);
}
catch(Exception exp){}
}
public boolean move(){
int m = -1,n=-1;
boolean successMove = false;
Point pStart = getAtPoint();
findIndex(pStart,allPoint); // 见后面的findIndex(Point p,Point[][] allPoint)方法
for(int i = 0;i
HandleImage类所创建的对象负责将一幅图像分成若干个小图像。
package ch7.data;
import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
public class HandleImage extends JComponent{
int imageWidth,imageHeight;
Toolkit tool;
public HandleImage(){
tool=getToolkit();
}
public Image [] getImages(Image image,int rows,int colums){
Image [] blockImage=new Image[rows*colums];
try{
imageWidth=image.getWidth(this);
imageHeight=image.getHeight(this);
int w=imageWidth/colums;
int h=imageHeight/rows;
int k=0; //把图像分成k份,即rows*colums份
PixelGrabber pg=null;
ImageProducer ip=null;
for(int i=0;i
Point类负责创建确定位置的对象,使用 Point对象可以确定 Block对象在PuzzlePad对象中的位置,即确定“方块”在“魔板”中的位置。
package ch7.data;
public class Point{
int x,y; //在坐标系中的x-坐标和y-坐标
boolean haveBlock; //点上是否有方块
Block block=null; //点上的方块
public Point(){
}
public Point(int x,int y){
this.x=x;
this.y=y;
}
public boolean isHaveBlock(){
return haveBlock;
}
public void setHaveBlock(boolean boo){
haveBlock=boo;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setBlock(Block block){
this.block=block;
}
public Block getBlock(){
return block;
}
}
VerifySuccess类所创建的对象负责验证用户是否按要求成功排列魔板中的方块。
package ch7.data;
public class VerifySuccess{
Point [][] point;
Object [] object;
public void setPoint(Point [][] point){
this.point=point;
}
public void setObject(Object [] object){
this.object=object;
}
public boolean isSuccess(){
if(point[point.length-1][point[0].length-1].getBlock()!=null) //如果右下角有方块
return false;
boolean boo=true;
int k=0;
for(int i=0;i
HandleMove类所创建的对象负责处理鼠标事件。
package ch7.view;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import ch7.data.Point;
import ch7.data.Block;
import ch7.data.HandleImage;
import ch7.data.VerifySuccess;
public class HandleMove extends JPanel implements MouseListener,ActionListener {
Point [][] point;
int spendTime=0;
javax.swing.Timer recordTime;
JTextField showTime;
VerifySuccess verify;
HandleMove(){
recordTime=new javax.swing.Timer(1000,this);
showTime = new JTextField(16);
showTime.setEditable(false);
showTime.setHorizontalAlignment(JTextField.CENTER);
showTime.setFont(new Font("楷体_GB2312",Font.BOLD,16));
JLabel hitMess=new JLabel("用鼠标单击方块",JLabel.CENTER);
hitMess.setFont(new Font("楷体_GB2312",Font.BOLD,18));
add(hitMess) ;
add(showTime);
setBackground(Color.cyan);
}
public void setPoint(Point [][] p){
point=p;
}
public void initSpendTime(){
recordTime.stop();
spendTime=0;
showTime.setText(null);
}
public void setVerifySuccess(VerifySuccess verify){
this.verify=verify;
}
public void mousePressed(MouseEvent e){
recordTime.start();
Block block=null;
block=(Block)e.getSource();
Point startPoint=block.getAtPoint();
int w=block.getBounds().width;
int h=block.getBounds().height;
if(block.move()){
Point pEnd = block.getAtPoint();//得到方块移动后所在点
int x = pEnd.getX();
int y = pEnd.getY();
block.setLocation(x,y);
block.setAtPoint(pEnd);
pEnd.setBlock(block);
pEnd.setHaveBlock(true);
startPoint.setHaveBlock(false);
}
}
public void actionPerformed(ActionEvent e){
spendTime++;
showTime.setText("您的用时:"+spendTime+"秒");
}
public void mouseReleased(MouseEvent e){
if(verify.isSuccess()){
recordTime.stop();
JOptionPane.showMessageDialog(this,"您成功了!","消息框",
JOptionPane.INFORMATION_MESSAGE );
}
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
}
PuzzlePad类创建的对象是 PuzzleGame类最重要的成员之一,代表“魔板”。
package ch7.view;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import ch7.data.Point;
import ch7.data.Block;
import ch7.data.HandleImage;
import ch7.data.VerifySuccess;
public class PuzzlePad extends JPanel{
Point [][] point;
Block [][] block;
int distance=56,grade,m=3,n=3;
HandleMove handleMove;
HandleImage handleImage;
VerifySuccess verifySuccess;
Image image;
boolean isDigitPlay;
public PuzzlePad(){
setBackground(Color.gray);
setLayout(null);
handleMove=new HandleMove();
handleMove.initSpendTime();
handleImage=new HandleImage();
verifySuccess=new VerifySuccess();
handleMove.setVerifySuccess(verifySuccess);
}
public HandleMove getHandleMove(){
return handleMove;
}
public void setImage(Image image){
this.image=image;
}
public void setGrade(int grade){
this.grade=grade;
if(grade==1){
m=3;
n=3;
}
else if(grade==2){
m=4;
n=4;
}
}
public int getGrade(){
return grade;
}
private void needInit(){
handleMove.initSpendTime();
removeAll();
point=new Point[m][n];
block=new Block[m][n];
int Hspace=distance,Vspace=distance;
for(int i=0;i numberList=new ArrayList();
for(int k=0;k imageList=new ArrayList();
Image [] blockImage=handleImage.getImages(image,m,n);
for(int k=0;k
这里我们创建test包,实现AppTest类来进行代码的测试,代码如下:
package ch7.test;
import ch7.data.*;
public class AppTest {
public static void main(String [] args) {
Point [][] point = new Point[3][3]; //3行3列的魔板中的点
for(int i=0;i
本次项目设计是通过 Java语言编制一个魔板游戏,它是一款经典的智力游戏。而Java语言是当今较为流行的网络编程语言,它具有面向对象、跨平台、分布应用等特点。这次设计,还有利于加深对 Java课程的进一步了解,也可以巩固所学 Java语言基本知识,增进 Java语言编辑基本功,掌握 JDK、Editplus、Idea、JCreator等开发工具的运用,拓宽常用类库的应用。使学生通过该教学环节与手段,把所学课程及相关知识加以融会贯通,全面掌握 Java语言的编程思想及面向对象程序设计的方法。