基于java的拼图小游戏
学习java也有一段时间了,但是一直处于控制台的编程阶段,乏味的控制台看久了有没有给人一种很枯燥乏味的感觉呢?于是乎博主开始自己学习java的swing组件,让我们的程序可以脱离控制台。好了废话不多说了,下面开始整理我的第一个小游戏——拼图。
拼图的原理其实很简单,首先我们得准备一张完整的图片,其关键过程在于如何分割图片,打乱图片次序,以及图片之间的移动交换,最后判断是否拼图成功。
按照上述关键过程我们开始逐一进行描述吧!
首先准备一张图片规格可以自定义在这里我选择300*300的图片:
因为本程序需要切割图片并把每一块作为一个具体的东西放在面板上,因此我们可以使用JButton按钮组件,把截取的小图一图标的形式显示在按钮组件上。所以在此我们先创建一个Cell类并继承JButton类:
<span style="font-size:12px;">/**
* 此类作为拼图的按钮类,每一张分割的图片
* 都是以一个按钮的形式存在的
*/
import javax.swing.Icon;
import javax.swing.JButton;
import com.direction.Direction;
public class Cell extends JButton {
/*
* 记录按钮的位置
*/
private int place;
/*
* 定义每个按钮的宽度即图片的固定宽度为100px
*/
public static final int WIDTH=100;
/*
* 构造每个图片按钮
* 传入图标和位置参数
*/
public Cell(Icon icon,int place){
this.setIcon(icon);
this.place=place;
this.setSize(WIDTH, WIDTH);//设置每个按钮的大小为100*100
}
/*
* 获得单元按钮的x坐标
*/
public int getButtonX(){
return this.getBounds().x;
}
/*
* 获得单元按钮的Y坐标
*/
public int getButtonY(){
return this.getBounds().y;
}
/*
* 获取图片的位置
*/
public int getPlace(){
return this.place;
}
/*
* 移动按钮的方法
*/
public void move(Direction d){
int x=this.getButtonX();
int y=this.getButtonY();
switch(d){
//向上移动
case UP:this.setLocation(x, y-WIDTH);
break;
//向下移动
case DOWN:this.setLocation(x, y+WIDTH);
break;
//向左移动
case LEFT:this.setLocation(x-WIDTH, y);
break;
//向右移动
case RIGHT:this.setLocation(x+WIDTH, y);
break;
}
}
}</span>
下面开始要进行图片的分割在这里用到了ImageIO类,BufferedImage类,首先我们得以流的形式把图片载入内存中,之后按照3*3的格式把整张图片分割成9张尺寸为100*100的矩形,在这里用到BufferedImage类中的getSubimage方法,该方法截取开始点的X,Y轴的坐标以及截取的width和height可以得到一个指定大小的图片,返回的也是一个BufferedImage对象。我们可以将每块小图片存放到按钮上,需要把BufferedImage对象转换成Icon对象
<span style="font-size:12px;"> //定义接收整张图片
BufferedImage bi=null;
//定义接收分割后的一张图片
BufferedImage newImage=null;
//定义图片的序号
int place;
//定义每张小图截取的左上点位置
int x=0;
int y=0;
//定义图标对象
Icon icon=null;
try {
//读取图片以流的形式载入内存
bi=ImageIO.read(new File("./image/pic.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
/*
* 开始分割图片把图片分割成9*9的每个张小图并装入数组里
*/
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
place=i*3+j;//计算图片编号
//计算截取的左上角xy坐标
x=j*100;
y=i*100;
newImage=bi.getSubimage(x,y , 100, 100);
//将图片装入cells数组
if(place+1!=9){
icon=new ImageIcon(newImage);
}else{
icon=new ImageIcon("./image/blank.jpg");//获取空白图片
}
//将图片装入按钮中
Cell cell=new Cell(icon, place);
cell.setLocation(x, y);
cells[place]=cell;//将按钮存入数组
}
}</span>
之后我们只需要将数组打乱即可,使用Random类<span style="font-size:12px;"> Random random=new Random();
for(int i=0;i<cells.length;i++){
/*
*获取两个随机数m,n
*/
int m=random.nextInt(cells.length);
int n=random.nextInt(cells.length);
while(m==n){
m=random.nextInt(cells.length);
n=random.nextInt(cells.length);
}
int x=cells[m].getButtonX();
int y=cells[m].getButtonY();
//交换两个按钮
cells[m].setLocation(cells[n].getButtonX(), cells[n].getButtonY());
cells[n].setLocation(x, y);
}</span>
之后为每个按钮注册监听
<span style="font-size:12px;"> //获取空白图片
if(cellBlank==null){
cellBlank=cells[cells.length-1];
for(int i=0;i<cells.length;i++){
//为每个按钮注册监听
cells[i].addMouseListener(this);
}
}</span>
下面关键的来了,我们需要实现按钮与空白图片的按钮之间的上下左右的移动,通过鼠标单击的方法获取每个触发事件的对象,因此我们需要实现MouseListener接口的mouseClicked方法:在此方法中实现我们的移动过程:<span style="font-size:12px;"> @Override
public void mouseClicked(MouseEvent e) {
//获得点击图片的按钮对象
Cell cell=(Cell)e.getSource();
int x=cell.getButtonX();//获得当前按钮对象的x坐标
int y=cell.getButtonY();//获得当前按钮对象的y坐标
Cell blank=cells[8];//获得空白按钮图片对象
/*
* 如果事件对象在空白图片的左边
* 那么对象事件右移并把空白区域左移
*/
if(x-blank.getButtonX()==-Cell.WIDTH&&y==blank.getButtonY()){
//调用按钮对象中的move方法实现两个按钮之间的交换
cell.move(Direction.RIGHT);
blank.move(Direction.LEFT);
}
/*
*如果事件对象在空白图片的右边
*那么对象事件左移并把空白区域右移
*/
else if(x-blank.getButtonX()==Cell.WIDTH&&y==blank.getButtonY()){
cell.move(Direction.LEFT);
blank.move(Direction.RIGHT);
}
/*
* 如果事件对象在空白图片的上边
*那么对象事件下移并把空白区域上移
*/
else if(y-blank.getButtonY()==-Cell.WIDTH&&x==blank.getButtonX()){
cell.move(Direction.DOWN);
blank.move(Direction.UP);
}
/*
* 如果事件对象在空白图片的下边
*那么对象事件上移并把空白区域下移
*/
else if(y-blank.getButtonY()==Cell.WIDTH&&x==blank.getButtonX()){
cell.move(Direction.UP);
blank.move(Direction.DOWN);
}
}</span>
至此我们的拼图就可以实现移动的功能了,此外对于方向的参数我这里使用了java中的枚举类只有4个参数:
<span style="font-size:12px;">public enum Direction {
UP,DOWN,LEFT,RIGHT;
}</span>
最后我们将我们的panel面板加入我们的主面板即可:public class PicFrame extends JFrame {
public PicFrame(){
super("拼图游戏");
this.getContentPane().setLayout(new BorderLayout());
setBounds(300, 300, 358, 414);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel=new JPanel(new BorderLayout());
this.getContentPane().add(panel, BorderLayout.NORTH);
final GamePanel gp=new GamePanel();
JButton btn=new JButton("开始");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
gp.randomButton();
}
});
panel.add(btn,BorderLayout.CENTER);
this.getContentPane().add(gp,BorderLayout.CENTER);
}
public static void main(String[] args) {
new PicFrame().setVisible(true);
}
}
最终效果如下: