开发工具:eclipse,jdk1.8
- 概述
拼图游戏是广受欢迎的一种智力游戏,它的变化多端,难度不一,让人百玩不厌。拼图游戏是把一张图片分成多个小块,根据难度一般有9块(3×3)、16块(4×4)、25块(5×5)等,然后随机打乱图块的顺序,重新把拼图还原成原来的样子。这次我做的这个拼图小游戏就是一个简单的3×3小拼图,可以实现一般的拼图功能,并且可以选择不同的图片。操作也是非常简单,鼠标点击“开始游戏”进行游戏,然后用鼠标点击拼图块完成拼图就可以了。
- 程序分析。
该游戏程序由MyMainFrame、MyCanvas、Cell三部分组成,其中Cell类是继承的按钮类,并加上相应图片形成拼图方格, MyCanvas类是一个面板,加载Cell类的对象(方格),是这三个类中的核心,并且定义了接收鼠标事件以及开始游戏的方法,MyMainFrame类是主程序,初始化了面板,并在面板上添加了按钮。
- 程序设计,
3.1程序目标
-
- 将原始图片分割成大小相同的9个小方格,每个小方格加载相应的图片;
- 通过鼠标点击小方格来进行移动;
- 用户界面具有标题,并且在上方面板上添加“开始游戏”、“查看图片”、“选择图片”按钮;
- 原始图片至少有5张以上,进行游戏时可以选择任意一张;
- 用户界面美观、简洁、友好,符合日常软件的使用规范;
- 当完成拼图是会弹出消息框显示“恭喜你完成拼图”。
-
①Cell模块 首先Cell类继承了JButton类,然后构造了宽100,高100的方格,this.setSize(100,100)就是设定方格大小的语句。然后还定义了方格移动的方法,当参数direction为“UP”时,方格向上移动,用this.setLocation()实现;当参数direction为“DOWN”时,方格向下移动;当参数direction为“LEFT”时,方格向左移动;当参数direction为“RIHGT”时,方格向右移动。 主要方法代码如下: Cell(Icon icon){构造方格 super(icon);//调用父类构造函数 this.setSize(100,100);//每块方格拼图设置为宽100,高100 } Move方法用来进行方格的移动: public void move(String direction,int sleep){//方格的移动 if(direction=="UP"){//上移 this.setLocation(this.getBounds().x,this.getBounds().y-100); }else if(direction=="DOWN"){//下移 this.setLocation(this.getBounds().x,this.getBounds().y+100); }else if(direction=="LEFT"){//左移 this.setLocation(this.getBounds().x-100,this.getBounds().y); }else{//右移 this.setLocation(this.getBounds().x+100,this.getBounds().y); } } ②MyCanvas模块 MyCanvas类首先继承JPanel类,并实现MouseListener接口。MyCanvas类构造了一个宽400,高400的容器,用this.setSize(400,400)实现。接着构造了一个宽100,高100的空方格区域放在第三行每三列,然后为9个方格加载图片,并初使化坐标,形成三行三列,最后还要移除最后一个方格。模块还定义了一个方法isFinish来判断拼图是否拼合成功,成功返回true,否则返回false。 模块定义了Start方法来开始游戏,使方格随机排序。还定义了方格的鼠标事件mousePressed(MouseEvent arg0)来进行点击方格跟空方格的交换。当完成拼图时,用JOptionPane.showMessageDialog(this,"恭喜你完成拼图!")弹出消息框显示“恭喜你完成拼图!” 主要方法代码如下: MyCanvas方法用来初始化方格并给方格加载图片: public MyCanvas() {初始化方格,并给每个方格加载图片 this.setLayout(null);//设置此容器的布局管理器 this.setSize(400,400); cellNull=new Rectangle(200,200,100,100);//空方格区域在第三行每三列,宽100,高100 cell=new Cell[9]; Icon icon; for (int i = 0; i < 3; i++) {//为9个方格加载图片,并初使化坐标,形成三行三列 for(int j=0;j<3;j++){ icon=new ImageIcon("pictrue/pic_"+pictureID+"_"+(i*3+j+1)+".jpg"); cell[i*3+j]=new Cell(icon); cell[i*3+j].setLocation(j*100,i*100);//初始化方格坐标 this.add(cell[i*3+j]);//添加方格 } } this.remove(cell[8]);//移除最后一个多余的方格 } isFinish方法用来判断拼图是否拼合成功: public boolean isFinish(){//判断拼图是否拼合成功 for(int i=0;i<8;i++){ int x=cell[i].getBounds().x; int y=cell[i].getBounds().y; if(y/100*3+x/100!=i)//依次判断每个方格是否在最初的位置 return false; } return true; } Start方法用来打乱方格顺序,进行随机排序 public void Start(){//对方格进行重新排列,打乱顺序 while(cell[0].getBounds().x<=100&&cell[0].getBounds().y<=100){//当第一个方格距左上角较近时 int x=cellNull.getBounds().x; int y=cellNull.getBounds().y; int direction=(int)(Math.random()*4);//产生0-4,对应空方格的上下左右移动 if(direction==0){//LEFT空方格左移动,与左侧方格互换位置,左侧方格右移动 x-=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){//依次寻找空方格左侧的方格 cell[j].move("RIGHT",100);//左侧方格右移动 cellNull.setLocation(x,y);//空方格左移动 break;//找到后跳出for循环 } } } }else if(direction==1){//RIGHT x+=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("LEFT",100); cellNull.setLocation(x,y); break; } } } }else if(direction==2){//UP y-=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("DOWN",100); cellNull.setLocation(x,y); break; } } } }else{//DOWN y+=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("UP",100); cellNull.setLocation(x,y); break; } } } } } if(!hasAddActionListener)//如果尚未添加动作事件,则添加 for(int i=0;i<8;i++)//为第个方格添加动作事件,这样单击按钮就能移动了 cell[i].addMouseListener(this); hasAddActionListener=true; } mousePressed方法用来进行点击方格跟空方格的交换: public void mousePressed(MouseEvent arg0) {//方格的鼠标事件 Cell button=(Cell)arg0.getSource();//确定点击的方格 int x1=button.getBounds().x;//得到所单击方格的坐标 int y1=button.getBounds().y; int x2=cellNull.getBounds().x;//得到空方格的坐标 int y2=cellNull.getBounds().y; if(x1==x2&&y1-y2==100)//进行比较,如果满足条件则进行交换 button.move("UP",100); else if(x1==x2&&y1-y2==-100) button.move("DOWN",100); else if(x1-x2==100&y1==y2) button.move("LEFT",100); else if(x1-x2==-100&&y1==y2) button.move("RIGHT",100); else return;//不满足就不进行任何处理 cellNull.setLocation(x1,y1);//空方格移动到点击的方格坐标 this.repaint();//重绘此组件 if(this.isFinish()){//进行是否完成的判断 JOptionPane.showMessageDialog(this,"恭喜你完成拼图!");//调出 消息对话框 for(int i=0;i<8;i++) cell[i].removeMouseListener(this);//如果已完成,撤消鼠标事件,鼠标单击方格不在起作用 hasAddActionListener=false; } } ③MyMainFrame模块 MyMainFrame类先继承了JFrame类并实现ActionListener接口。用MyMainFrame方法初始化面板,在上方面板上添加了“开始游戏”、“查看图片”、“选择图片”三个按钮,并在主面板上坐标(0,0)位置加载了宽300高300的图片,用label.setBounds(0,0,300,300); panelPreview.add(label)实现。用语句panelNorth.setBackground(Color.gray)将上方面板设置成灰色,用语句this.setTitle("拼图小游戏")设置界面窗口标题为拼图小游戏。this.setResizable(false)语句设置窗体为不可以由用户调整大小。再用actionPerformed(ActionEvent arg0)方法对三个按钮事件进行处理。当点击“开始游戏”的按钮,就执行Start方法即初始化游戏;当点击“查看图片”按钮,主面板显示图片,并把“显示图片”按钮改成“返回游戏”按钮,当再次点击“返回游戏”按钮时,就会回到游戏并且“返回游戏”按钮也会变回“查看图片”按钮;当点击“选择图片”按钮时,就会弹出选择方框,方框里有6张图片可以选择,分别是小猫、小猪、云彩、QQ、动漫、花朵。 主要方法代码如下: actionPerformed 方法是对“开始游戏”、“查看图片”、“选择图片”三个按钮进行相对应的功能设置: public void actionPerformed(ActionEvent arg0) {//对三个按钮事件的处理 // TODO 自动生成方法存根 Button button=(Button)arg0.getSource(); if(button==start){ myCanvas.Start(); }else if(button==preview){ if(button.getLabel()=="查看图片"){ container.remove(myCanvas); container.add(panelPreview); panelPreview.updateUI();//利用当前外观的值重置UI属性 container.repaint(); button.setLabel("返回游戏"); }else{ container.remove(panelPreview); container.add(myCanvas); container.repaint(); button.setLabel("查看图片"); } }else if(button==set){//修改所选图片 Choice pic = new Choice(); pic.add("小猫"); pic.add("小猪"); pic.add("云彩"); pic.add("QQ"); pic.add("动漫"); pic.add("花朵"); int i=JOptionPane.showConfirmDialog(this, pic, "选择图片", JOptionPane.OK_CANCEL_OPTION); if(i==JOptionPane.YES_OPTION){//当选择YES时 MyCanvas.pictureID=pic.getSelectedIndex()+1;//把选择的图片索引号返回给pictureID myCanvas.reLoadPictrue();//重新加载图片 Icon icon=new ImageIcon("pictrue/pic_"+MyCanvas.pictureID+".jpg"); JLabel label=new JLabel(icon); label.setBounds(0,0,300,300); panelPreview.removeAll(); panelPreview.add(label); panelPreview.repaint(); } }