Java游戏开发——拼图游戏经典版
游戏介绍:
拼图游戏是一款经典的益智游戏,游戏难度分为 简单、正常、困难 三种难度,分别对应3*3,4*4,5*5布局,游戏开始前图片被随机打乱,空块位于最右下角,玩家通过点击空块周围图片或者按键方式对图片和空块进行相互交换,直到所有图片都回到原位即为游戏胜利。
本次制作的拼图游戏运行界面如下:
使用素材文件夹:
素材和完整源码链接:https://pan.baidu.com/s/1ws1S4rYVK5U95TU5FMA5UQ 提取码:kvtg
游戏设计的思路
对拼图界面的图像信息可以采用二维数组map进行存储,数组存储的是图片ID,拼图完成的map数组存储的内容应该为从左到右,从上到下,图片ID顺序为1~8,最右下角的数 组元素存储的图片ID为-1(BLANK_STATE)。所有的移动操作可以简化为对map的移动操作,每次移动完成调用repaint()对图片按ID进行绘画即可。使用文本存储历史记录,每次过关对当前步数和历史记录进行比较和更新。考虑到数组map要求打乱后可以通过移动被还原,所以对数组的打乱必须有所讲究,这里我们采用系统对原有图片执行10000次上下左右按键事件来对图片进行打乱,最后再将空块移动到最右下角,这样图片就顺利地做到了随机打乱。
图片的获取及显示:
先根据关卡level来获取关卡图片,不同的关卡将分成不同数量的小块,假如是简单难度3*3地图,小图片的宽w是大图片的宽的三分之一,小图片的高h是大图片的高的三分之一,第i张图片的左上角起点的x值为图片所在列数*小图片宽(i%3*w),y值为图片所在行数*小图片高(i/3*h):
private void getPics() {BufferedImage bufferedImage = null;int width = 0,height = 0;try {bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));width = bufferedImage.getWidth();height = bufferedImage.getHeight();} catch (IOException e) {e.printStackTrace();}if(level==EASY){pics = new Image[9];int w = width/3;int h = height/3;for(int i=0;i<8;i++){int x = i%3*w;int y = i/3*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else if(level==NORMAL){pics = new Image[16];int w = width/4;int h = height/4;for(int i=0;i<15;i++){int x = i%4*w;int y = i/4*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else{pics = new Image[25];int w = width/5;int h = height/5;for(int i=0;i<24;i++){int x = i%5*w;int y = i/5*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}}public void paint(Graphics g){g.clearRect(0, 0, this.getWidth(), this.getHeight());for(int i=0;i<map.length;i++)for(int j=0;j<map.length;j++){ if(map[i][j]!=BLANK_STATE){//画图g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);}} }
游戏逻辑
对玩家执行不同的操作进行分别处理:
①当玩家鼠标点击
当玩家鼠标点击的小图片位于空块上下左右方时,点击的小图片与空块交换位置,否则点击无效。
②当玩家按键移动
当空块位于第一行时,moveDown()无效;
当空块位于最后一行时,moveUp()无效;
当空块位于第一列时,moveRight()无效;
当空块位于最后一列时,moveLeft()无效;
此处的moveLeft()指的是小图片移动的方向,也就是空块移动的反方向。鼠标点击事件的移动可以复用按键事件的移动方法,只需要将点击的小图片与数组下标进行转换,再判断下调用哪个方法即可。
public void mousePressed(MouseEvent e) {// TODO Auto-generated method stubint x = e.getX()-leftX;int y = e.getY()-leftY;if(x<0||y<0||x>600||y>600){//超出地图范围return ;}//存储数组行列下标int i = y/W;int j = x/W;if(blank_x == i-1&&blank_y == j){//空块在当前点击块的上侧moveUp();}else if(blank_x == i+1&&blank_y == j){//空块在当前点击块的下侧moveDown();}else if(blank_x == i&&blank_y == j-1){//空块在当前点击块的左侧moveLeft();}else if(blank_x == i&&blank_y == j+1){//空块在当前点击块的右侧moveRight();}else{return ;}repaint();isWin(); }public void keyPressed(KeyEvent e) {// TODO Auto-generated method stubif(e.getKeyCode() == KeyEvent.VK_UP&&blank_x!=level+1){//上moveUp();}else if(e.getKeyCode() == KeyEvent.VK_DOWN&&blank_x!=0){//下moveDown();}else if(e.getKeyCode() == KeyEvent.VK_LEFT&&blank_y!=level+1){//左 moveLeft();}else if(e.getKeyCode() == KeyEvent.VK_RIGHT&&blank_y!=0){//右moveRight();}else{return ;}repaint();isWin();}
小图片的移动
交换小图片与空块的值,并对空块的数组下标重新赋值:
//空块与上一格交换 private void moveDown(){map[blank_x][blank_y] = map[blank_x-1][blank_y];map[blank_x-1][blank_y] = BLANK_STATE;blank_x = blank_x-1;step++;HelpPanel.nowStep.setText(step+"");}//空块与下一格交换private void moveUp(){map[blank_x][blank_y] = map[blank_x+1][blank_y];map[blank_x+1][blank_y] = BLANK_STATE;blank_x = blank_x+1; step++;HelpPanel.nowStep.setText(step+"");}//空块与左一格交换private void moveRight(){map[blank_x][blank_y] = map[blank_x][blank_y-1];map[blank_x][blank_y-1] = BLANK_STATE;blank_y = blank_y-1;step++;HelpPanel.nowStep.setText(step+"");}//空块与右一格交换private void moveLeft(){map[blank_x][blank_y] = map[blank_x][blank_y+1];map[blank_x][blank_y+1] = BLANK_STATE;blank_y = blank_y+1; step++;HelpPanel.nowStep.setText(step+"");}
打乱地图信息
使用Math.Random()获取随机值,各个方向按键事件的概率是1/4,当符合条件时执行移动方法并且移动次数+1,移动10000次实现随机打乱地图。
private void RandomTheMap() {int i =0;//尝试移动一万次 while(i<10000){int rate = (int) (Math.random()*100);if(rate<25&&blank_x!=level+1){moveUp();i++;}else if(rate<50&&blank_x!=0){moveDown();i++;}else if(rate<75&&blank_y!=level+1){moveLeft();i++;}else if(rate<100&&blank_y!=0){moveRight();i++;} }//再将空块移动到最右下角while(blank_x<level+1){moveUp();}while(blank_y<level+1){moveLeft();}step=0;}
判断输赢
将现有map信息与正确的map信息一一对比,如果都相等,过关,比较当前记录和历史记录,如果刷新历史记录进行记录的更新,然后询问是否开始下一关。如果开始下一关,进行level++并对地图及面板信息进行初始化:
private void isWin() {boolean flag = true;for(int i=0;i<successMap.length;i++){for(int j=0;j<successMap.length;j++){if(map[i][j] != successMap[i][j]){flag = false;break;}}}if(flag){String msg;int type;int choice;int record;String title;switch(level){//通关,是否进入下一关case EASY:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过简单关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜你通过简单关卡,完成步数是"+step+"\n是否要进入下一关?";}type = JOptionPane.YES_NO_OPTION;title = "过关";choice = 0;choice = JOptionPane.showConfirmDialog(null, msg,title,type);if(choice==1){System.exit(0);}else if(choice == 0){level++;map = mapUtil.getMap(level);successMap = mapUtil.getMap(level);record = mapUtil.getRecord(level);//获取正常难度的历史记录initializeMap();//初始化地图相关变量信息RandomTheMap();//打乱图案顺序step = 0;HelpPanel.histotyStep.setText(record+"");HelpPanel.panelCenter.setSuccessPic(level);HelpPanel.nowLevel.setText("正常");HelpPanel.nowStep.setText(step+"");getPics();this.addKeyListener(this);this.addMouseListener(this);repaint();};break;case NORMAL:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过正常关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜你通过正常关卡,完成步数是"+step+"\n是否要进入下一关?";}type = JOptionPane.YES_NO_OPTION;title = "过关";choice = 0;choice = JOptionPane.showConfirmDialog(null, msg,title,type);if(choice==1){System.exit(0);}else if(choice == 0){level++;map = mapUtil.getMap(level);successMap = mapUtil.getMap(level);initializeMap();//初始化地图相关变量信息RandomTheMap();//打乱图案顺序getPics();step = 0;record = mapUtil.getRecord(level);//获取困难难度的历史记录。HelpPanel.histotyStep.setText(record+"");HelpPanel.panelCenter.setSuccessPic(level);HelpPanel.nowStep.setText(step+"");HelpPanel.nowLevel.setText("困难");this.addKeyListener(this);this.addMouseListener(this);repaint();};break;case HARD:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过困难关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record;JOptionPane.showMessageDialog(this, msg);mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜通过困难关卡,完成步数是"+step;JOptionPane.showMessageDialog(this, msg);};break;}}}
历史记录的读写
采用文本形式对记录进行保存,初始情况下,读取记录的时候如果没有记录文件进行文件的新建并初始所有历史记录为9999步;记录的保存采用两个逗号对三个关卡的历史记录进行分割,读取后进行array.split(",")分割操作;写入时,先清空原有文本信息,再将记录合成字符串写入文件。
//获取关卡历史记录public int getRecord(int level){File file = new File("D://GameRecordAboutSwing");if(!file.exists()){file.mkdirs();}File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");try{if(!record.exists()){//如果不存在,新建文本record.createNewFile();fos = new FileOutputStream(record);dos = new DataOutputStream(fos);String s = "9999,9999,9999";dos.writeBytes(s);System.out.println(record.isFile());;}//读取记录fis = new FileInputStream(record);dis = new DataInputStream(fis);String str = dis.readLine();array = str.split(",");}catch(Exception e){e.printStackTrace();}finally{try {if(fis!=null)fis.close();if(dis!=null)dis.close(); if(fos!=null)fos.close();if(dos!=null)dos.close(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return Integer.parseInt(array[level-1]);}//更新关卡历史记录public void writeRecord(int level,int step){File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");try {//清空原有记录FileWriter fileWriter =new FileWriter(record);fileWriter.write("");fileWriter.flush();fileWriter.close();//重新写入文本fos = new FileOutputStream(record);dos = new DataOutputStream(fos);array[level-1] = step+"";String s = array[0]+","+array[1]+","+array[2];dos.writeBytes(s);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {if(fos!=null)fos.close();if(dos!=null)dos.close(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
到这里核心的游戏逻辑及游戏面板的相关内容已经说明完了,涉及辅助面板类的东西会有些错综复杂,这里就不详细介绍了。
完整源码如下:
MapUtil类:
package 人物拼图;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;public class MapUtil {int[][] map;FileInputStream fis = null;FileOutputStream fos = null;DataInputStream dis = null;DataOutputStream dos = null;String array[] = null;int level = 1;public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;public int[][] getMap(int level){switch(level){case EASY:map = new int[3][3];for(int i=0;i<3;i++)for(int j=0;j<3;j++){map[i][j] = 3*i+j+1;}map[2][2] = BLANK_STATE;;break;case NORMAL:map=new int[4][4];for(int i=0;i<4;i++)for(int j=0;j<4;j++){map[i][j] = 4*i+j+1;}map[3][3] = BLANK_STATE;break;case HARD:map=new int[5][5];for(int i=0;i<5;i++)for(int j=0;j<5;j++){map[i][j] = 5*i+j+1;}map[4][4] = BLANK_STATE;break;}return map;}//获取关卡历史记录public int getRecord(int level){File file = new File("D://GameRecordAboutSwing");if(!file.exists()){file.mkdirs();}File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");try{if(!record.exists()){//如果不存在,新建文本record.createNewFile();fos = new FileOutputStream(record);dos = new DataOutputStream(fos);String s = "9999,9999,9999";dos.writeBytes(s);System.out.println(record.isFile());;}//读取记录fis = new FileInputStream(record);dis = new DataInputStream(fis);String str = dis.readLine();array = str.split(",");}catch(Exception e){e.printStackTrace();}finally{try {if(fis!=null)fis.close();if(dis!=null)dis.close(); if(fos!=null)fos.close();if(dos!=null)dos.close(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return Integer.parseInt(array[level-1]);}//更新关卡历史记录public void writeRecord(int level,int step){File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");try {//清空原有记录FileWriter fileWriter =new FileWriter(record);fileWriter.write("");fileWriter.flush();fileWriter.close();//重新写入文本fos = new FileOutputStream(record);dos = new DataOutputStream(fos);array[level-1] = step+"";String s = array[0]+","+array[1]+","+array[2];dos.writeBytes(s);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {if(fos!=null)fos.close();if(dos!=null)dos.close(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
MapUtil类主要用做对地图数组信息的初始化以及历史记录的读写。
GamePanel类
package 人物拼图;import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;public class GamePanel extends JPanel implements ActionListener ,MouseListener,KeyListener{Image pics[];int leftX=50,leftY=50;int level,W;int[][] map;int[][] successMap;//最后结果int blank_x,blank_y;//记录空白块的数组下标int step = 0;MapUtil mapUtil = new MapUtil();int record;//存储当前关卡记录public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;public GamePanel(int level){setSize(600, 600);this.level = level;map = mapUtil.getMap(level);successMap = mapUtil.getMap(level);initializeMap();//初始化地图相关变量信息RandomTheMap();//打乱图案顺序this.setVisible(true); this.addKeyListener(this);this.addMouseListener(this);this.setFocusable(true);getPics();record = mapUtil.getRecord(level);HelpPanel.histotyStep.setText(record+"");HelpPanel.nowStep.setText(step+"");repaint();}public void paint(Graphics g){g.clearRect(0, 0, this.getWidth(), this.getHeight());for(int i=0;i<map.length;i++)for(int j=0;j<map.length;j++){ if(map[i][j]!=BLANK_STATE){//画图g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);}} }private void initializeMap(){switch(level){case EASY:blank_x=2;blank_y=2;W = 200;;break;case NORMAL:blank_x=3;blank_y=3;W = 150;;break;case HARD:blank_x=4;blank_y=4;W = 120;;break;}}private void RandomTheMap() {int i =0;//尝试移动一万次 while(i<10000){int rate = (int) (Math.random()*100);if(rate<25&&blank_x!=level+1){moveUp();i++;}else if(rate<50&&blank_x!=0){moveDown();i++;}else if(rate<75&&blank_y!=level+1){moveLeft();i++;}else if(rate<100&&blank_y!=0){moveRight();i++;} }//再将空块移动到最右下角while(blank_x<level+1){moveUp();}while(blank_y<level+1){moveLeft();}step=0;}//空块与上一格交换private void moveDown(){map[blank_x][blank_y] = map[blank_x-1][blank_y];map[blank_x-1][blank_y] = BLANK_STATE;blank_x = blank_x-1;step++;HelpPanel.nowStep.setText(step+"");}//空块与下一格交换private void moveUp(){map[blank_x][blank_y] = map[blank_x+1][blank_y];map[blank_x+1][blank_y] = BLANK_STATE;blank_x = blank_x+1; step++;HelpPanel.nowStep.setText(step+"");}//空块与左一格交换private void moveRight(){map[blank_x][blank_y] = map[blank_x][blank_y-1];map[blank_x][blank_y-1] = BLANK_STATE;blank_y = blank_y-1;step++;HelpPanel.nowStep.setText(step+"");}//空块与右一格交换private void moveLeft(){map[blank_x][blank_y] = map[blank_x][blank_y+1];map[blank_x][blank_y+1] = BLANK_STATE;blank_y = blank_y+1; step++;HelpPanel.nowStep.setText(step+"");}private void getPics() {BufferedImage bufferedImage = null;int width = 0,height = 0;try {bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));width = bufferedImage.getWidth();height = bufferedImage.getHeight();} catch (IOException e) {e.printStackTrace();}if(level==EASY){pics = new Image[9];int w = width/3;int h = height/3;for(int i=0;i<8;i++){int x = i%3*w;int y = i/3*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else if(level==NORMAL){pics = new Image[16];int w = width/4;int h = height/4;for(int i=0;i<15;i++){int x = i%4*w;int y = i/4*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else{pics = new Image[25];int w = width/5;int h = height/5;for(int i=0;i<24;i++){int x = i%5*w;int y = i/5*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}}@Overridepublic void keyTyped(KeyEvent e) {// TODO Auto-generated method stub}@Overridepublic void keyPressed(KeyEvent e) {// TODO Auto-generated method stubif(e.getKeyCode() == KeyEvent.VK_UP&&blank_x!=level+1){//上moveUp();}else if(e.getKeyCode() == KeyEvent.VK_DOWN&&blank_x!=0){//下moveDown();}else if(e.getKeyCode() == KeyEvent.VK_LEFT&&blank_y!=level+1){//左 moveLeft();}else if(e.getKeyCode() == KeyEvent.VK_RIGHT&&blank_y!=0){//右moveRight();}else{return ;}repaint();isWin();}@Overridepublic void keyReleased(KeyEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseClicked(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stubint x = e.getX()-leftX;int y = e.getY()-leftY;if(x<0||y<0||x>600||y>600){//超出地图范围return ;}//存储数组行列下标int i = y/W;int j = x/W;if(blank_x == i-1&&blank_y == j){//空块在当前点击块的上侧moveUp();}else if(blank_x == i+1&&blank_y == j){//空块在当前点击块的下侧moveDown();}else if(blank_x == i&&blank_y == j-1){//空块在当前点击块的左侧moveLeft();}else if(blank_x == i&&blank_y == j+1){//空块在当前点击块的右侧moveRight();}else{return ;}repaint();isWin(); }private void isWin() {boolean flag = true;for(int i=0;i<successMap.length;i++){for(int j=0;j<successMap.length;j++){if(map[i][j] != successMap[i][j]){flag = false;break;}}}if(flag){String msg;int type;int choice;int record;String title;switch(level){//通关,是否进入下一关case EASY:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过简单关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜你通过简单关卡,完成步数是"+step+"\n是否要进入下一关?";}type = JOptionPane.YES_NO_OPTION;title = "过关";choice = 0;choice = JOptionPane.showConfirmDialog(null, msg,title,type);if(choice==1){System.exit(0);}else if(choice == 0){level++;map = mapUtil.getMap(level);successMap = mapUtil.getMap(level);record = mapUtil.getRecord(level);//获取正常难度的历史记录initializeMap();//初始化地图相关变量信息RandomTheMap();//打乱图案顺序step = 0;HelpPanel.histotyStep.setText(record+"");HelpPanel.panelCenter.setSuccessPic(level);HelpPanel.nowLevel.setText("正常");HelpPanel.nowStep.setText(step+"");getPics();this.addKeyListener(this);this.addMouseListener(this);repaint();};break;case NORMAL:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过正常关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜你通过正常关卡,完成步数是"+step+"\n是否要进入下一关?";}type = JOptionPane.YES_NO_OPTION;title = "过关";choice = 0;choice = JOptionPane.showConfirmDialog(null, msg,title,type);if(choice==1){System.exit(0);}else if(choice == 0){level++;map = mapUtil.getMap(level);successMap = mapUtil.getMap(level);initializeMap();//初始化地图相关变量信息RandomTheMap();//打乱图案顺序getPics();step = 0;record = mapUtil.getRecord(level);//获取困难难度的历史记录。HelpPanel.histotyStep.setText(record+"");HelpPanel.panelCenter.setSuccessPic(level);HelpPanel.nowStep.setText(step+"");HelpPanel.nowLevel.setText("困难");this.addKeyListener(this);this.addMouseListener(this);repaint();};break;case HARD:this.removeKeyListener(this);this.removeMouseListener(this);record = mapUtil.getRecord(level);//历史记录if(step<record){msg = "恭喜你通过困难关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record;JOptionPane.showMessageDialog(this, msg);mapUtil.writeRecord(level, step);//更新历史记录}else{msg = "恭喜通过困难关卡,完成步数是"+step;JOptionPane.showMessageDialog(this, msg);};break;}}}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stub}}
GamePanel类主要涉及游戏面板的小图片的读取和显示,以及全部游戏的逻辑。
SuccessPanel类:
package 人物拼图;import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;import javax.imageio.ImageIO;
import javax.swing.JPanel;public class SuccessPanel extends JPanel{int level;Image[] pics;int[][] map;int W ; MapUtil mapUtil;private int leftX=10;private int leftY=150;public static final int EASY=1,NORMAL=2,HARD=3,BLANK_STATE=-1;public SuccessPanel(int level){setSuccessPic(level);}public void setSuccessPic(int level) {mapUtil = new MapUtil();this.level = level;BufferedImage bufferedImage = null;int width = 0,height = 0;try {bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));width = bufferedImage.getWidth();height = bufferedImage.getHeight();} catch (IOException e) {e.printStackTrace();}if(level == EASY){pics = new Image[9];map = mapUtil.getMap(level);W = 40;int w = width/3;int h = height/3;for(int i=0;i<8;i++){int x = i%3*w;int y = i/3*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else if(level == NORMAL){pics = new Image[16];map = mapUtil.getMap(level);W = 30;int w = width/4;int h = height/4;for(int i=0;i<15;i++){int x = i%4*w;int y = i/4*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}else{pics = new Image[25];map = mapUtil.getMap(level);W = 24;int w = width/5;int h = height/5;for(int i=0;i<24;i++){int x = i%5*w;int y = i/5*h;pics[i] = bufferedImage.getSubimage(x, y, w, h); }}repaint();}public void paint(Graphics g){for(int i=0;i<map.length;i++)for(int j=0;j<map.length;j++){ if(map[i][j]!=BLANK_STATE){//画图g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);}}}}
SuccessPanel类负责游戏运行界面右下角完整拼图顺序的小图片显示;
HelpPanel类:
package 人物拼图;import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;public class HelpPanel extends JPanel {private int level = 1;public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;static JLabel nowStep = new JLabel("0");static JLabel histotyStep = new JLabel("9999");static JLabel nowLevel = new JLabel();JLabel levelLabel = new JLabel("当前难度:");JLabel nowStepLabel = new JLabel("当前步数:");JLabel historyStepLabel = new JLabel("历史记录:");JButton button1 = new JButton("退出");BorderLayout panel1 = new BorderLayout();//右侧JPanel panelNorth = new JPanel(new GridLayout(4,2,10,30));static SuccessPanel panelCenter = new SuccessPanel(1);public HelpPanel(int level){setLevel(level);this.setVisible(true);this.setLayout(new BorderLayout());//当前面板panelNorth.add(levelLabel);panelNorth.add(nowLevel);panelNorth.add(nowStepLabel);panelNorth.add(nowStep);panelNorth.add(historyStepLabel);panelNorth.add(histotyStep);//历史记录panelNorth.add(button1);this.add(panelNorth,BorderLayout.NORTH);this.add(panelCenter,BorderLayout.CENTER);button1.addMouseListener(new MouseAdapter(){public void mouseClicked(MouseEvent e){System.exit(1);}});;}public void setLevel(int level){this.level = level;panelCenter.setSuccessPic(level);if(level == EASY){nowLevel.setText("简单");}else if(level == NORMAL){nowLevel.setText("正常");}else{nowLevel.setText("困难");}}}
HelpPanel类负责游戏运行界面右边辅助面板的显示,其中装载了SuccessPanel;
GameClient类:
package 人物拼图;import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;public class GameClient extends JFrame{GamePanel panel2;public GameClient(){HelpPanel panel = new HelpPanel(1);panel2 = new GamePanel(1);//难度简单panel2.setLayout(new BorderLayout());this.getContentPane().setLayout(new BorderLayout());this.getContentPane().add(panel,BorderLayout.EAST);this.getContentPane().add(panel2,BorderLayout.CENTER);this.setSize(850,750);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setTitle("人物拼图游戏");this.setVisible(true);}public static void main(String[] args) {new GameClient();}}
GameClient类是游戏窗口类,装载了游戏面板和辅助面板,用来开始游戏。
源码已经粘贴完毕,最后再展示两张游戏运行截图:
Java游戏开发——拼图游戏经典版相关推荐
- Java实现人物拼图游戏
Java实现人物拼图游戏│附代码 Original 清华计算机学堂 清华计算机学堂 Yesterday 收录于话题 #数据库 7个 拼图游戏指将一幅图片分割成若干拼块,并随机打乱顺序,当将所有拼块都放 ...
- iOS cocos2d 2游戏开发实战(第3版)
<iOS cocos2d 2游戏开发实战(第3版)> 基本信息 原书名:Learn cocos2d 2: Game Development for iOS 作者: (美)Steffen I ...
- 《Android 游戏开发大全(第二版)》——6.4节角色扮演游戏
本节书摘来自异步社区<Android 游戏开发大全(第二版)>一书中的第6章,第6.4节角色扮演游戏,作者吴亚峰 , 于复兴 , 杜化美,更多章节内容可以访问云栖社区"异步社区& ...
- HTML5 Canvas游戏开发实战 PDF扫描版
HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读 ...
- java演练 猜奇偶小游戏开发 DB游戏必输的设计
java演练 猜奇偶小游戏开发 DB游戏必输的设计 阶段一,视频 https://www.ixigua.com/6870390946270446088?logTag=J_BVJOm_LIpQ-hWYY ...
- 微信小程序开发的游戏《拼图游戏》
微信小程序开发的游戏<拼图游戏> 代码直接考进去就能用 pintu.js // pintu.js Page({/*** 页面的初始数据*/data: {},initGame: functi ...
- 初学者开发iOS游戏的入门必备用书——iOS 5 cocos2d游戏开发实战(第2版)
如果想接触iOS游戏开发,今天笔者就推荐一本"大杀器"--<iOS 5 cocos2d游戏开发实战(第2版)>(当当链接) 为零基础的"设想过自己写个电脑游戏 ...
- iOS 5 cocos2d游戏开发实战(第2版)
<iOS 5 cocos2d游戏开发实战(第2版)> 基本信息 作者: [美]Steffen Itterheim Andreas Low [作译者介绍] 译者: 同济大学苹果俱乐部 丛书名 ...
- Java实现小拼图游戏
今天整理之前的项目,发现了在大二上学期的java课程设计中编写的智能拼图小游戏,觉得有意思,所以打算写篇文章和大伙分享分享. 一.项目功能 1)本游戏是一个Java语言的拼图游戏,有一个格子是空的,其 ...
最新文章
- go语言笔记——调试还很弱,用gdb来做?可用panic和defer。格式化代码使用gofmt,貌似我的vim插件是自带...
- zookeeper 创建临时顺序节点_Zookeeper学习笔记
- 牛客网暑期ACM多校训练营(第一场)J Different Integers
- SAP Commerce Cloud SmartEdit 学习笔记
- An ffmpeg and SDL Tutorial
- Web browser的发展演变
- MVC下实现LayUI分页的Demo
- Android 全局悬浮按钮,悬浮按钮点击事件
- deeplearning4j的学习
- 修改kubernetes服务 nodeport 类型的端口范围
- 快逸报表数据库密码加密解决方案
- Visual Assist X 10.6.1837完美破解版(带VS2010破解)
- 绿幕抠图支持网页、PPT背景类型
- 稳压二极管原理、参数、动态电阻特性
- 三维地图前端arcgis_WebGIS简单实现一个区域炫酷的3D立体地图效果
- 2.4 导集,闭集,闭包
- 世界淡水资源占水资源的多少_世界上可用淡水资源到底是多少
- 计算机专业1分钟能打多少字,一分钟打多少字算合格?
- 应用在低功耗SMPS中的GaN/氮化镓
- Win11桌面图标的小盾牌怎么去掉?
热门文章
- windows系统设置QOS限速分配,巧妙网络资源利用率提高网络服务质量,任务进程限速出站上传速率
- LCD与DLP投影仪原理简介
- JQuery基础学习
- oracle安装前注意事项,Oracle安装与重装注意事项
- 代码发芽网:无需插件支持Blog代码高亮,支持近百种编程语言
- 三工业控制系统的安全性分析
- 武大计算机专硕难还是学硕难,考研难度有多大?看完武大考生的信息,我很庆幸自己已经上岸...
- 传媒行业的新媒体之路:机遇与挑战共存
- npm ERR path C:\Users\H\Desktop\renren-fast-vue\node_modules\node-sass
- 科普 | 什么是网络专线