IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java拼图游戏,老程序员花两天搞定,你呢? -> 正文阅读

[Java知识库]Java拼图游戏,老程序员花两天搞定,你呢?

java拼图游戏,老程序花2天时间搞定

作者简介

作者名:编程界明世隐
简介: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;
}

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

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

代码获取方式

帮忙文章【点赞】 +【 收藏】+【关注】+【评论】 后,加我主页微信或者私聊我,我发给你!

更多精彩

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在线考试系统

另外

为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,原件129元现价 29 元先到先得,有兴趣的小伙伴可以了解一下

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-20 14:57:12  更:2021-08-20 14:57:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 1:35:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码