Java拼图游戏

592 阅读5分钟

作者简介

作者名:编程界明世隐
简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!

系列目录

1. Java俄罗斯方块
2. Java五子棋小游戏
3. 老Java程序员花一天时间写了个飞机大战
4. Java植物大战僵尸
5. 老Java程序员花2天写了个连连看
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战 10. Java迷宫小游戏

引言:

前几天群里的小伙伴问我Java小游戏啥时候做完,怎么还没更新,说能不能提个建议,然后就说明哥能不能做个拼图游戏。 哈哈,像我这么帅气的博主向来都不太会拒绝人的,于是,它来了它来了。

效果图

在这里插入图片描述

实现思路

  1. 绘制窗口。
  2. 加载好所有的图片。
  3. 绘制按钮、边框等。
  4. 创建右边预览小图。
  5. 将大图切片,并展示。
  6. 点击开始按钮,打乱图片位置。
  7. 加入鼠标移入和点击事件,处理移入和点击效果。
  8. 点击交换后判断顺序,如果顺序正确则提示成功。

代码实现

创建窗口

首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。

package main;

import java.awt.Color;
import javax.swing.JFrame;
/**
 *窗体类
 */
public class GameFrame extends JFrame {
	//构造方法
	public GameFrame(){
		setTitle("拼图游戏");//设置标题
		setSize(874, 412);//设置窗体大小
		getContentPane().setBackground(new Color(0,0,0));//加上黑色背景
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭后进程退出
		setLocationRelativeTo(null);//居中
		setResizable(false);//不允许变大
		//setVisible(true);//设置显示窗体
	}
}

创建面板容器GamePanel继承至JPanel

package main;

import javax.swing.JMenuBar;
import javax.swing.JPanel;

/*
 * 画布类
 */
public class GamePanel extends JPanel {
	private JMenuBar jmb = null;
	private GameFrame mainFrame = null;
	private GamePanel panel = null;
	//构造方法
	public GamePanel(GameFrame mainFrame){
		this.setLayout(null);
		this.setOpaque(false);
		this.mainFrame=mainFrame;
		this.panel =this;
	}
}

再创建一个Main类,来启动这个窗口,用来启动。

package main;
//Main类
public class Main {

	public static void main(String[] args) {
		GameFrame frame = new GameFrame();
		GamePanel panel = new GamePanel(frame);
		frame.add(panel);
		frame.setVisible(true);
	}
}

右键执行这个Main类,窗口建出来了(加的黑色背景不好看) 在这里插入图片描述

加载好所有的图片

package common;

import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
//图片加载
public class ImageValue {
	//图片路径
	private static String path = "/images/";
	//图片集合
	public static Map<Integer,BufferedImage> images = new HashMap<Integer,BufferedImage>();
	
	//初始化图片方法
	public static void init() {
		try {
			//加载16张图片,并放入Map中
			for (int i = 1; i <= 16; i++) {
				images.put(i,ImageIO.read(ImageValue.class.getResource(path+i+".jpeg")));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

在构造函数中调用,待会就可以直接使用了。 在这里插入图片描述

创建边框

//绘制边框
private void drawBorder(Graphics g) {
	BasicStroke bs_2=new BasicStroke(12L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER);
	Graphics2D g_2d=(Graphics2D)g;
	g_2d.setColor(new Color(128,128,128));
	g_2d.setStroke(bs_2);
	g_2d.drawRect(6, 6, 652, 372);
}
//绘制右边预览边框
private void drawViewBorder(Graphics g) {
	BasicStroke bs_2=new BasicStroke(12L,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER);
	Graphics2D g_2d=(Graphics2D)g;
	g_2d.setColor(new Color(128,128,128));
	g_2d.setStroke(bs_2);
	g_2d.drawRect(658, 6, 204, 372);
}

在GamePanel重写 paint 方法,并调用这两个方法,如下:

@Override
public void paint(Graphics g) {
	super.paint(g);
	//绘制边框
	drawBorder(g);
	//绘制右边预览边框
	drawViewBorder(g);
}

运行效果如下: 在这里插入图片描述

难度系数、预览图等文字

难度系数默认是3 在这里插入图片描述 创建难度系数、预览图等

//绘制预览图文字
private void drawViewText(Graphics g) {
	//得分
	Color oColor = g.getColor();
	oColor = g.getColor();
	g.setColor(Color.white);
	g.setFont(new Font("思源宋体", Font.BOLD, 18));
	g.drawString("预览图",668, 40);
	g.setColor(oColor);		
}
//绘制难度系数显示
private void drawGradeText(Graphics g) {
	//得分
	Color oColor = g.getColor();
	oColor = g.getColor();
	g.setColor(Color.white);
	g.setFont(new Font("思源宋体", Font.BOLD, 18));
	g.drawString("难度系数:"+grade+"",668, 210);
	g.setColor(oColor);		
}

在paint方法中调用:

@Override
public void paint(Graphics g) {
	super.paint(g);
	//绘制边框
	drawBorder(g);
	//绘制右边预览边框
	drawViewBorder(g);
	//绘制预览图文字
	drawViewText(g);
	//绘制难度系数显示
	drawGradeText(g);
}

在这里插入图片描述

创建按钮

创建4个按钮的代码如下:

//初始化
private void init() {
	// 开始按钮
	JButton btnStart = new JButton();
	btnStart.setFont(new Font("思源宋体", Font.BOLD, 18));
	btnStart.setFocusPainted(false);
	btnStart.setText("开始");
	btnStart.setBounds(668, 300, 80, 33);
	btnStart.setBorder(BorderFactory.createRaisedBevelBorder());
	this.add(btnStart);
	btnStart.addActionListener(this);
	btnStart.setActionCommand("start");
	
	//切换按钮
	JButton nextStart = new JButton();
	nextStart.setFont(new Font("思源宋体", Font.BOLD, 18));
	nextStart.setFocusPainted(false);
	nextStart.setText("换换");
	nextStart.setBounds(768, 300, 80, 33);
	nextStart.setBorder(BorderFactory.createRaisedBevelBorder());
	this.add(nextStart);
	nextStart.addActionListener(this);
	nextStart.setActionCommand("next");
	
	
	//难度减按钮
	JButton gradeDecrease = new JButton();
	gradeDecrease.setFont(new Font("思源宋体", Font.BOLD, 18));
	gradeDecrease.setFocusPainted(false);
	gradeDecrease.setText("难度减");
	gradeDecrease.setBounds(668, 250, 80, 33);
	gradeDecrease.setBorder(BorderFactory.createRaisedBevelBorder());
	this.add(gradeDecrease);
	gradeDecrease.addActionListener(this);
	gradeDecrease.setActionCommand("gradeDecrease");
	
	//难度加按钮
	JButton gradeIncrease = new JButton();
	gradeIncrease.setFont(new Font("思源宋体", Font.BOLD, 18));
	gradeIncrease.setFocusPainted(false);
	gradeIncrease.setText("难度加");
	gradeIncrease.setBounds(768, 250, 80, 33);
	gradeIncrease.setBorder(BorderFactory.createRaisedBevelBorder());
	this.add(gradeIncrease);
	gradeIncrease.addActionListener(this);
	gradeIncrease.setActionCommand("gradeIncrease");
}

此时可以看到开发工具中,报红,因为没有实现ActionListener 在这里插入图片描述 实现 ActionListener 并重新方法 actionPerformed 在这里插入图片描述

@Override
public void actionPerformed(ActionEvent e) {
	String command = e.getActionCommand();
	UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
	UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
	if("start".equals(command)){//开始
		
	}else if("next".equals(command)){//切换
		
	}else if("gradeDecrease".equals(command)){//难度减
		
	}else if("gradeIncrease".equals(command)){//难度加
		
	}
}

在构造函数中调用 init方法,运行效果如下: 在这里插入图片描述

实现右侧预览小图

创建 ViewImage 类,这个类很简单就是通过调用draw方法在指定的位置、指定的宽高、绘制指定的图片。

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
/*
 * 预览图
 */
public class ViewImage {
	private int x = 0;// x坐标
	private int y = 0;// y坐标
	private int w = 0;// 宽
	private int h = 0;// 高
	private BufferedImage img = null;// 图片对象
	
	public ViewImage(BufferedImage img,int x,int y,int w,int h){
		this.img=img;
		this.x=x;
		this.y=y;
		this.w=w;
		this.h=h;
	}
	
	// 图片绘制方法
	public void draw(Graphics g) {
		g.drawImage(img, x, y, w, h, null);
	}
}

创建预览图实例

private void createViewImage() {
	BufferedImage img = ImageValue.images.get(imageKey);
	int x=664;
	int y=62;
	int w=192;
	int h=108;
	viewImage = new ViewImage(img, x, y, w, h);		
}

注意需加入成员变量

private ViewImage viewImage = null;
private int imageKey = 1;//图片下标,默认1

在GamePanel的构造方法中调用

public GamePanel(GameFrame mainFrame){
	this.setLayout(null);
	this.setOpaque(false);
	this.mainFrame=mainFrame;
	this.panel =this;
	
	//图片的加载
	ImageValue.init();
	//初始化
	init();
	//创建预览图
	createViewImage();
}

绘制预览图的方法

//绘制预览图
private void drawViewImage(Graphics g) {
	if(viewImage!=null){
		viewImage.draw(g);
	}		
}

在paint方法中调用

@Override
public void paint(Graphics g) {
	super.paint(g);
	//绘制边框
	drawBorder(g);
	//绘制右边预览边框
	drawViewBorder(g);
	//绘制预览图文字
	drawViewText(g);
	//绘制难度系数显示
	drawGradeText(g);
	
	//绘制预览图
	drawViewImage(g);
}

运行效果如下: 在这里插入图片描述

将大图切片

图片绘制方法介绍: g.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);

参数说明: img - 绘制指定图像。如果 img 为 null,不执行任何操作。 dx1 - 目标矩形第一个角的 x 坐标。 dy1 - 目标矩形第一个角的 y 坐标。 dx2 - 目标矩形第二个角的 x 坐标。 dy2 - 目标矩形第二个角的 y 坐标。 sx1 - 源矩形第一个角的 x 坐标。 sy1 - 源矩形第一个角的 y 坐标。 sx2 - 源矩形第二个角的 x 坐标。 sy2 - 源矩形第二个角的 y 坐标。

创建 SmallImage 类

属性名说明
dx1目标显示左上角x坐标
dy1目标显示左上角y坐标
dWidth目标宽度,与dx1相加计算第2个点dx2
dHeight目标高度,与dy1相加计算第2个点dy2
sx1源图左上角x坐标
sy1源图左上角y坐标
sWidth源宽度,与sx1相加计算第2个点sx2
sHeight源高度,与sy1相加计算第2个点sy2
i下标i(切片交换时候用的)
j下标j(切片交换时候用的)
oi原始下标i(用来比较顺序)
oj原始下标j(用来比较顺序)
img图片对象
selected选择状态,根据选择的状态来显示小图片的边框
disXx方向长
disYy方向高

注意点:

  1. 根据的 oi,oj 来计算源的两个点坐标,因为一旦实例话oi,oj 就是固定的,也就是来源变。
  2. 根据 i,j 来计算目标的两个点坐标,当我们执行拼图交换位置的时候,就是交换 i,j ,所以达到交换的目的。
//初始化
public void init() {
	int start = 12;//初始偏移量,根据边框来偏移
	
	//根据传入的i j 来计算目标的两个点坐标
	int x = start+i*disX;
	int y = start+j*disY;
	
	this.dx1 = x;
	this.dy1 = y;
	this.dWidth = disX;
	this.dHeight = disY;
	
	//根据的oi oj 来计算源的两个点坐标
	int sx = start+oi*disX;
	int sy = start+oj*disY;
	this.sx1 = sx;
	this.sy1 = sy;
	this.sWidth = disX;
	this.sHeight = disY;
}
  1. 绘制完图片后要根据图显示类型来显示小边框。
//图片绘制方法
public void draw(Graphics g) {
	//每次绘制之前要重新计算
	init();
	
	/*
	 *  img - 要绘制的指定图像。如果 img 为 null,则此方法不执行任何操作。
		dx1 - 目标矩形第一个角的 x 坐标。
		dy1 - 目标矩形第一个角的 y 坐标。
		dx2 - 目标矩形第二个角的 x 坐标。
		dy2 - 目标矩形第二个角的 y 坐标。
		sx1 - 源矩形第一个角的 x 坐标。
		sy1 - 源矩形第一个角的 y 坐标。
		sx2 - 源矩形第二个角的 x 坐标。
		sy2 - 源矩形第二个角的 y 坐标。
	 */
	g.drawImage(img, dx1, dy1, dx1+dWidth, dy1+dHeight, sx1, sy1, sx1+sWidth, sy1+sHeight,
			null);
	
	if(selected==0){//默认黑色
		g.setColor(new Color(0,0,0));
		g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
	}else if(selected==1){//鼠标移入白色
		g.setColor(new Color(255,255,255));
		g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
	}else if(selected==2){//选中,黄色
		g.setColor(new Color(209,146,17));
		g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
	}
}
  1. 加入判断鼠标是否在小图片范围内的方法
//判断是否在小图片范围内
public boolean isPoint(int x,int y){
	//左上角
	int  x1 = this.dx1;
	int  y1 = this.dy1;
	//右下角
	int  x2 = this.dx1 + dWidth;
	int  y2 = this.dy1 + dHeight;
	
	
	return x>x1&&y>y1&&x<x2&&y<y2;
}

SmallImage类完整代码

package main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class SmallImage {
	private int dx1 = 0;// x坐标
	private int dy1 = 0;// y坐标
	private int dWidth = 0;// 宽
	private int dHeight = 0;// 高
	private int sx1 = 0;// x坐标
	private int sy1 = 0;// y坐标
	private int sWidth = 0;// 宽
	private int sHeight = 0;// 高
	private int i = 0;// 下标i
	private int j = 0;// 下标j
	private int oi = 0;// 原始下标i
	private int oj = 0;// 原始下标j
	private BufferedImage img = null;// 图片对象
	private int selected = 0;//选择状态
	private int disX;//x方向长
	private int disY;//y方向高
	// 构造方法
	public SmallImage(BufferedImage img, int i, int j, int disX, int disY) {
		this.img = img;
		this.i = this.oi = i;
		this.j = this.oj = j;
		this.disX=disX;
		this.disY=disY;
	}
	//初始化
	public void init() {
		int start = 12;
		int x = start+i*disX;
		int y = start+j*disY;
		
		this.dx1 = x;
		this.dy1 = y;
		this.dWidth = disX;
		this.dHeight = disY;
		
		int sx = start+oi*disX;
		int sy = start+oj*disY;
		this.sx1 = sx;
		this.sy1 = sy;
		this.sWidth = disX;
		this.sHeight = disY;
	}

	// 图片绘制方法
	public void draw(Graphics g) {
		//每次绘制之前要重新计算
		init();
		
		/*
		 *  img - 要绘制的指定图像。如果 img 为 null,则此方法不执行任何操作。
			dx1 - 目标矩形第一个角的 x 坐标。
			dy1 - 目标矩形第一个角的 y 坐标。
			dx2 - 目标矩形第二个角的 x 坐标。
			dy2 - 目标矩形第二个角的 y 坐标。
			sx1 - 源矩形第一个角的 x 坐标。
			sy1 - 源矩形第一个角的 y 坐标。
			sx2 - 源矩形第二个角的 x 坐标。
			sy2 - 源矩形第二个角的 y 坐标。
		 */
		g.drawImage(img, dx1, dy1, dx1+dWidth, dy1+dHeight, sx1, sy1, sx1+sWidth, sy1+sHeight,
				null);
		
		if(selected==0){//默认黑色
			g.setColor(new Color(0,0,0));
			g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
		}else if(selected==1){//鼠标移入白色
			g.setColor(new Color(255,255,255));
			g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
		}else if(selected==2){//选中,黄色
			g.setColor(new Color(209,146,17));
			g.drawRect(dx1, dy1, dWidth-1, dHeight-1);
		}
	}
	
	//判断是否在小图片范围内
	public boolean isPoint(int x,int y){
		//左上角
		int  x1 = this.dx1;
		int  y1 = this.dy1;
		//右下角
		int  x2 = this.dx1 + dWidth;
		int  y2 = this.dy1 + dHeight;
		
		
		return x>x1&&y>y1&&x<x2&&y<y2;
	}
	
	public int getI() {
		return i;
	}
	public void setI(int i) {
		this.i = i;
	}
	public int getJ() {
		return j;
	}
	public void setJ(int j) {
		this.j = j;
	}
	public int getOi() {
		return oi;
	}
	public void setOi(int oi) {
		this.oi = oi;
	}
	public int getOj() {
		return oj;
	}
	public void setOj(int oj) {
		this.oj = oj;
	}
	public int getSelected() {
		return selected;
	}
	public void setSelected(int selected) {
		this.selected = selected;
	}
}

GamePanel类中加入成员变量

private String gameFlag="end";//游戏状态
private int grade=3;//难道系数,最小为3,最大为10
private int w=640;//图片的宽
private int h=360;//图片的高
private SmallImage[][] sImages;//图片二维数组
List<SmallImage> imageList = new ArrayList<SmallImage>();//图片集合
private SmallImage curSmallImage;//当前选择的小图片

创建切片方法

//对图片进行切片
private void sliceImage(){
	
	int disX = this.w/grade;//小图片的宽
	int disY = this.h/grade;//小图片的高
	
	//初始化小图片对象        			
	SmallImage smallImage;
	BufferedImage img = ImageValue.images.get(imageKey);
	
	sImages = new SmallImage[grade][grade];
	for(int i=0;i<grade;i++){
		for(int j=0;j<grade;j++){
			smallImage = new SmallImage(img,i,j,disX, disY);
			sImages[i][j]=smallImage;
			imageList.add(smallImage);
		}
	}
}

构造函数调用此方法

public GamePanel(GameFrame mainFrame){
	this.setLayout(null);
	this.setOpaque(false);
	this.mainFrame=mainFrame;
	this.panel =this;
	
	//图片的加载
	ImageValue.init();
	//初始化
	init();
	//创建预览图
	createViewImage();
	//切片
	sliceImage();
}

绘制这些切片图形

//绘制小图片
	private void drawSmallImages(Graphics g) {
		SmallImage smallImage;
		for(int i=0;i<grade;i++){
			for(int j=0;j<grade;j++){
				smallImage = sImages[i][j];
				if(smallImage!=null){
					smallImage.draw(g);
				}
			}
		}
	}

paint方法中调用,注意drawSmallImages放到前面,因为涉及到边框绘制,如果放到后面拼图的边框会变的很粗,也可以做别的处理,我这里就取巧了。

@Override
public void paint(Graphics g) {
	super.paint(g);
	//绘制小图片
	drawSmallImages(g);
	//绘制边框
	drawBorder(g);
	//绘制右边预览边框
	drawViewBorder(g);
	//绘制预览图文字
	drawViewText(g);
	//绘制难度系数显示
	drawGradeText(g);
	
	//绘制预览图
	drawViewImage(g);
}

运行一下: 在这里插入图片描述

加入鼠标事件

移动事件,就是在图片的范围内,设置selected属性为1,然后重绘就行。

//鼠标点击、移动事件处理
private void createMouseListener() {
	MouseAdapter mouseAdapter = new MouseAdapter() {
		@Override
		public void mouseMoved(MouseEvent e) {
			if(!"start".equals(gameFlag)) return ;
			//获取鼠标坐标
			int x = e.getX();
			int y = e.getY();
			SmallImage smallImage;
			for(int i=0;i<grade;i++){
				for(int j=0;j<grade;j++){
					smallImage = sImages[i][j];
					if(smallImage!=null){
						if(curSmallImage==smallImage){
							//针对当前选择的小图片不做处理
							continue;
						}
						if(smallImage.isPoint(x, y)){
							//鼠标移入,设置边框白色
							smallImage.setSelected(1);
						}else{
							//设置边框默认黑色
							smallImage.setSelected(0);
						}
					}
				}
			}
			//重绘
			repaint();
		}
	};
	
	addMouseMotionListener(mouseAdapter);
	addMouseListener(mouseAdapter);
}

注意在构造中调用哦 在这里插入图片描述 给几个按钮先添加好方法

@Override
	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();
		UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
		UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
		if("start".equals(command)){//开始
			restart();
		}else if("next".equals(command)){//切换
			next();
		}else if("gradeDecrease".equals(command)){//难度减
			gradeDecrease();
		}else if("gradeIncrease".equals(command)){//难度加
			gradeIncrease();
		}
	}

实现这些方法,都比较简单,就不解释了,上代码:

//难度减
private void gradeDecrease() {
	if(grade<=3){//最小为3
		return ;
	}
	//数组清空
	imageList.clear();
	//清空二维数组
	clearImages(sImages);
	//先清空,再-- 不然数据没完全清空
	grade--;
	//切片
	sliceImage();
	//重新绘制
	repaint();
}

//难度加
private void gradeIncrease() {
	if(grade>=10){//最大为10
		return ;
	}
	//数组清空
	imageList.clear();
	//清空二维数组
	clearImages(sImages);
	//先清空,再++ 不然会报错
	grade++;	
	//切片
	sliceImage();
	//重新绘制
	repaint();
}

//切换图片
void next(){
	gameFlag = "end";
	//图片切换到下一张
	imageKey++;
	//到了最后则切回第一张
	if(imageKey>16){
		imageKey=1;
	}
	//数组清空
	imageList.clear();
	//清空二维数组
	clearImages(sImages);
	//创建预览图
	createViewImage();
	//切片
	sliceImage();
	//重新绘制
	repaint();
}
//重新开始
void restart() {
	gameFlag = "start";
	//当前选择图片设置为null
	curSmallImage = null;
	//清空二维数组
	clearImages(sImages);
	//随机排序,打乱拼图
	Collections.shuffle(imageList);
	//将排序后的图片添加到二维数组中
	addImages();
	//重新绘制
	repaint();
}
//将排序后的图片添加到二维数组中
private void addImages() {
	SmallImage smallImage;
	int n=0;
	for(int i=0;i<grade;i++){
		for(int j=0;j<grade;j++){
			smallImage = imageList.get(n);
			smallImage.setI(i);
			smallImage.setJ(j);
	
			sImages[i][j]=smallImage;
			n++;
		}
	}
}

//清空指定二维数组
void clearImages(SmallImage[][] imgs){
	for(int i=0;i<grade;i++){
		for(int j=0;j<grade;j++){
			imgs[i][j]=null;
		}
	}
}

//游戏胜利
public void gameWin() {
	gameFlag = "end";
	//弹出结束提示
	UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
	UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
    JOptionPane.showMessageDialog(mainFrame, "你成功了,太棒了!");
}

测试一下鼠标移入事件 在这里插入图片描述 处理鼠标点击事件

  1. 点击后判断是否已经有选择,如果没有则当前图片设置为已选择,并设置selected为2。
  2. 如果已经有选择的拼图块,则互相交换,交换就是交换 i 和 j即可。
  3. 交换完成后selected都设置为0,并且存储选择的对象设置为null。
  4. 每次交换完成后要进行差异比较,看拼图是否完成。
  5. 右键取消已经选择的处理。
@Override
public void mouseClicked(MouseEvent e) {
	if(!"start".equals(gameFlag)) return ;
	
	int buttonType = e.getButton();
	if(buttonType==2){//滚轮
		return ;
	}else if(buttonType==1){//左键
		boolean diffFlag =false;//是否要判断拼图完成
		//获取鼠标坐标
		int x = e.getX();
		int y = e.getY();
		SmallImage smallImage;
		for(int i=0;i<grade;i++){
			for(int j=0;j<grade;j++){
				smallImage = sImages[i][j];
				if(smallImage!=null){
					if(smallImage.isPoint(x, y)&& smallImage.getSelected()!=2){
						if(curSmallImage!=null){//交换
							//将curSmallImage 的i j临时存储
							int ti = curSmallImage.getI();
							int tj = curSmallImage.getJ();
							//把smallImage的i j 设置给curSmallImage
							curSmallImage.setI(smallImage.getI());
							curSmallImage.setJ(smallImage.getJ());
							//把curSmallImage的i j 设置给smallImage
							smallImage.setI(ti);
							smallImage.setJ(tj);
							//将两个边框都设置为默认
							curSmallImage.setSelected(0);
							smallImage.setSelected(0);
							//交换完 curSmallImage 置空
							curSmallImage = null;
							diffFlag =true;
						}else {//标记为当前
							curSmallImage = smallImage;
							//设置边框红色
							smallImage.setSelected(2);
						}
					}
				}
			}
		}
		//重绘
		repaint();
		
		//每次交换完要判断拼图是否完成
		if(diffFlag && diff()){
			gameWin();
			return;
		}
	}else if(buttonType==3){//右键
		//取消选择
		if(curSmallImage!=null){
			curSmallImage.setSelected(0);
			curSmallImage=null;
			//重绘
			repaint();
		}
	}
}

差异判断,比较每一个小图片的 i与oi,j与oj,如果都相同表示拼图完成 。

//差异比较 true表示没有差异
private boolean diff() {
	//比较每一个小图片的 i与oi,j与oj,如果都相同表示拼图完成 
	SmallImage smallImage;
	for(int i=0;i<grade;i++){
		for(int j=0;j<grade;j++){
			smallImage = sImages[i][j];
			if(smallImage!=null){
				//一旦有一个不成立,就表示没完成
				if(!(smallImage.getI()==smallImage.getOi() && 
						smallImage.getJ()==smallImage.getOj())){
					return  false;
				}
			}
		}
	}
	return true;
}

到这里基本就完成了,图片切换和难度系数的修改就不说明了。

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。

代码获取方式:

帮忙文章【点赞】 +【 收藏】+【关注】+【评论】 后,加V:qq283582761,我发给你!

更多精彩

1. Java俄罗斯方块
2. Java五子棋小游戏
3. 老Java程序员花一天时间写了个飞机大战
4. Java植物大战僵尸
5. 老Java程序员花2天写了个连连看
6. Java消消乐(天天爱消除)
7. Java贪吃蛇小游戏
8. Java扫雷小游戏
9. Java坦克大战
10. Java迷宫小游戏

相关阅读

1. JavaWeb图书管理系统
2. JavaWeb学生宿舍管理系统
3. JavaWeb在线考试系统