1. 程式人生 > >Java遊戲開發——拼圖遊戲經典版

Java遊戲開發——拼圖遊戲經典版

遊戲介紹:

拼圖遊戲是一款經典的益智遊戲,遊戲難度分為 簡單、正常、困難 三種難度,分別對應3*3,4*4,5*5佈局,遊戲開始前圖片被隨機打亂,空塊位於最右下角,玩家通過點選空塊周圍圖片或者按鍵方式對圖片和空塊進行相互交換,直到所有圖片都回到原位即為遊戲勝利。

本次製作的拼圖遊戲執行介面如下:

 

 

使用素材資料夾:

遊戲設計的思路

對拼圖介面的影象資訊可以採用二維陣列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 stub
		
		int 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 stub
		if(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 block
					e.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 block
			e.printStackTrace();
		}finally{
		     try {
				if(fos!=null)
		    	 fos.close();
				if(dos!=null)
				 dos.close();				
		     } catch (IOException e) {
				// TODO Auto-generated catch block
				e.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 block
					e.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 block
			e.printStackTrace();
		}finally{
		     try {
				if(fos!=null)
		    	 fos.close();
				if(dos!=null)
				 dos.close();				
		     } catch (IOException e) {
				// TODO Auto-generated catch block
				e.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);	    		
	    	}
	    	
	    }
	    
	}


	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		if(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();
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
		int 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;
			}
			
		}
		
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public 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類是遊戲視窗類,裝載了遊戲面板和輔助面板,用來開始遊戲。

原始碼已經貼上完畢,最後再展示兩張遊戲執行截圖: