Java 拼图游戏

概要:

拼图游戏是一个Applet程序。游戏可以将一张大图打乱成9张小图,然后在游戏中任挑选8张小图放在界面中几个任意的位置。通过鼠标来移动打乱的这8张图,使其恢复到预览中看到的效果。拼凑成功则游戏结束。本实例介绍如何制作拼图游戏,并可以选择多组打乱的图片进行拼凑。

| |目录

技术要点

实现拼图游戏的技术要点如下:

  • 使用Math包中的random()方法,可以使游戏中的图片每次初始的状态都不一样。创建按钮图标类来加载图片。运用鼠标的监听事件方法处理单击的图片。

  • Graphics类的getGraphics()方法和drawImage()等方法可以实现大图的分割。

准备工作

运行前请在项目根目录中新建picture文件夹,里面放置2张300X300像素的图片,命名分别为pic_1.jpg与pic_2.jpg

图片:

代码实现

ImagePieceTogether.java

package net.xsoftlab.baike;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class ImagePieceTogether extends JFrame implements ActionListener {// 操作实现拼图的游戏的类
	PanelOfImage imagePanel;// 声明图片面板
	JPanel panelOfSouth, panelOfLook;// //声明南侧面板和查看面板
	Button startButton;// 声明开始按钮
	Button lookButton;// 声明查看按钮
	Button chooseButton;// 选择按钮
	Container container;// 容器,得到内容面板

	public ImagePieceTogether() {// 构造方法进行初始化
		container = this.getContentPane();// 获得内容面板
		startButton = new Button("开始");// 创建开始按钮
		startButton.addActionListener(this);// 添加监听事件
		lookButton = new Button("查看");
		lookButton.addActionListener(this);
		chooseButton = new Button("选择");
		chooseButton.addActionListener(this);
		panelOfLook = new JPanel();// 创建查看面板
		panelOfLook.setLayout(null);// 设置布局
		Icon icon = new ImageIcon("picture/pic_" + PanelOfImage.currentPID + ".jpg");// 创建图标
		JLabel label = new JLabel(icon);// 创建图标标签
		label.setBounds(0, 0, 300, 300);// 设置标签的位置
		panelOfLook.add(label);// 添加标签
		panelOfSouth = new JPanel();// 创建南侧面板
		panelOfSouth.setBackground(Color.red);// 设置背景颜色
		panelOfSouth.add(startButton);// 添加开始按钮
		panelOfSouth.add(lookButton);// 添加查看按钮
		panelOfSouth.add(chooseButton);// 添加选择按钮
		imagePanel = new PanelOfImage();// 创建图片面板
		container.add(imagePanel, BorderLayout.CENTER);
		container.add(panelOfSouth, BorderLayout.SOUTH);
		this.setTitle("拼图游戏");// 设置标题
		this.setLocation(300, 200);// 设置位置
		this.setSize(308, 365);// 设置大小
		this.setResizable(false);// 设置是否可以通过某个用户操作调整
		this.setVisible(true);// 设置可视
		this.setDefaultCloseOperation(3);// 设置默认关闭操作
	}

	@Override
	public void actionPerformed(ActionEvent event) {// 按钮触发的事件
		Button button = (Button) event.getSource();// 获得事件按钮源
		if (button == startButton) {// 如果是开始按钮
			imagePanel.breakRank();// 调用图片方格打乱方法
		} else if (button == lookButton) {// 如果是查看事件
			if (button.getLabel() == "查看") {// 如果按钮标签为"查看"
				container.remove(imagePanel);// 容器移除图片面板
				container.add(panelOfLook);// 容器添加查看标签
				panelOfLook.updateUI();// 不用调整大小就可以出现新增删的组件
				container.repaint();// 重绘
				button.setLabel("返回");// 设置按钮标签
			} else {
				container.remove(panelOfLook);// 容器移除查看面板
				container.add(imagePanel);// 容器添加图片面板
				container.repaint();// 重绘
				button.setLabel("查看");
			}
		} else if (button == chooseButton) {// 如果是选择按钮
			Choice choice = new Choice();// 创建选择器
			choice.add("--小猫--");// 添加列表项
			choice.add("--QQ--");
			int i = JOptionPane.showConfirmDialog(this, choice, "选择图片", JOptionPane.OK_CANCEL_OPTION);// 弹出对话框
			if (i == JOptionPane.YES_OPTION) {// 选择对话框的确定按钮
				PanelOfImage.currentPID = choice.getSelectedIndex() + 1;// 获得列表项的编号
				imagePanel.reLoadPictrue();// 图片重载
				Icon icon = new ImageIcon("picture/pic_" + PanelOfImage.currentPID + ".jpg");// 获得图片图标
				JLabel label = new JLabel(icon);// 根据图标设置标签
				label.setBounds(0, 0, 300, 300);// 设置标签的方位
				panelOfLook.removeAll();
				panelOfLook.add(label);
				panelOfLook.repaint();
			}
		}
	}

	public static void main(String[] args) {// java程序主入口处
		new ImagePieceTogether();// 实例化对象
	}
}

PanelOfImage.java

package net.xsoftlab.baike;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
class PaneButton extends JButton {// 继承按钮类实现加图片的方格
	PaneButton(Icon icon) {// 构造方法进行初始化,设置图标
		super(icon);
		this.setSize(100, 100);// 设置每个方格的大小
	}
	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);
		}
	}
}
public class PanelOfImage extends JPanel implements MouseListener {// 图片面板加载方格对象
	boolean hasAddActionListener = false;// 设置方格动作监听器的标识
	PaneButton pane[];// 声明方格
	Rectangle nullPanel;// 声明空方格,没有添图片
	public static int currentPID = 1;// 当前选择的图片编号
	public PanelOfImage() {// 构造方法进行初始化
		this.setLayout(null);// 设置面板的布局为空
		this.setSize(400, 400);// 设置面板的大小
		nullPanel = new Rectangle(200, 200, 100, 100);// 设置空方格的位置
		pane = new PaneButton[9];// 创建九个方格
		Icon icon;// 声明图标
		for (int i = 0; i < 3; i++) {// 循环为每个方格加载图片
			for (int j = 0; j < 3; j++) {// 循环列
				icon = new ImageIcon("picture/pic_" + currentPID + "_"
						+ (i * 3 + j + 1) + ".jpg");// 创建图标
				pane[i * 3 + j] = new PaneButton(icon);// 创建方格在方格中加载图片
				pane[i * 3 + j].setLocation(j * 100, i * 100);// 设置方格的位置
				this.add(pane[i * 3 + j]);// 面板添加方格
			}
		}
		this.remove(pane[8]);// 移除多余的方格
	}
	public boolean isFinish() {// 判断是否拼凑成功
		for (int i = 0; i < 8; i++) {
			int x = pane[i].getBounds().x;
			int y = pane[i].getBounds().y;
			if (y / 100 * 3 + x / 100 != i)
				return false;
		}
		return true;
	}
	public void reLoadPictrue() {// 重新加载图片在重新选择图片时
		Icon icon;
		for (int i = 0; i < 3; i++) {// 循环为每个方格加载图片
			for (int j = 0; j < 3; j++) {
				icon = new ImageIcon("picture/pic_" + currentPID + "_"
						+ (i * 3 + j + 1) + ".jpg");
				pane[i * 3 + j].setIcon(icon);
			}
		}
	}
	public void breakRank() {// 方格打乱重新排序
		while (pane[0].getBounds().x <= 100 && pane[0].getBounds().y <= 100) {// 当第一个方格距左上角近时
			int x = nullPanel.getBounds().x;
			int y = nullPanel.getBounds().y;
			int direction = (int) (Math.random() * 4);// 随机产生一个数字对应空方格的上下左右移动
			if (direction == 0) {// 空方格左移动,与左侧方格互换位置,左侧方格右移动
				x -= 100;// 空主格左移
				if (test(x, y)) {
					for (int j = 0; j < 8; j++) {// 循环寻打左侧的按钮
						if ((pane[j].getBounds().x == x)
								&& (pane[j].getBounds().y == y)) {// 依次寻找左侧的按钮
							pane[j].move("RIGHT", 100);// 方格向右移动一格
							nullPanel.setLocation(x, y);// 重新设置空方格的位置
							break;// 跳出循环
						}
					}
				}
			} else if (direction == 1) {// 空方格右移动
				x += 100;
				if (test(x, y)) {
					for (int j = 0; j < 8; j++) {
						if ((pane[j].getBounds().x == x)
								&& (pane[j].getBounds().y == y)) {
							pane[j].move("LEFT", 100);// 方格向左移动一格
							nullPanel.setLocation(x, y);
							break;
						}
					}
				}
			} else if (direction == 2) {// 空方格上移动
				y -= 100;
				if (test(x, y)) {
					for (int j = 0; j < 8; j++) {
						if ((pane[j].getBounds().x == x)
								&& (pane[j].getBounds().y == y)) {
							pane[j].move("DOWN", 100);// 方格向下移动一格
							nullPanel.setLocation(x, y);
							break;
						}
					}
				}
			} else {// 空方格下移动
				y += 100;
				if (test(x, y)) {
					for (int j = 0; j < 8; j++) {
						if ((pane[j].getBounds().x == x)
								&& (pane[j].getBounds().y == y)) {
							pane[j].move("UP", 100);// 方格向上移动一格
							nullPanel.setLocation(x, y);
							break;
						}
					}
				}
			}
		}
		if (!hasAddActionListener)// 判断是否添加动作事件
			for (int i = 0; i < 8; i++) {// 循环为每个方格添加动作事件
				pane[i].addMouseListener(this);
			}
		hasAddActionListener = true;
	}
	private boolean test(int x, int y) {// 检测方格是否在指定的范围内移动
		if ((x >= 0 && x <= 200) || (y >= 0 && y <= 200))
			return true;
		else
			return false;
	}
	public void mouseClicked(MouseEvent arg0) {// 鼠标点击时调用
	}
	public void mouseEntered(MouseEvent arg0) {// 鼠标进入组件区域时调用
	}
	public void mouseExited(MouseEvent arg0) {// 控制鼠标不能移动出面板的范围
	}
	public void mouseReleased(MouseEvent arg0) {// 鼠标按键在组件上释放时调用
	}
	public void mousePressed(MouseEvent event) {// 鼠标按下时调用
		PaneButton button = (PaneButton) event.getSource();// 获得鼠标按的方格按钮
		int x1 = button.getBounds().x;// 获得该方格按钮的横坐标
		int y1 = button.getBounds().y;// 获得该方格按钮的纵坐标
		int nullDir_X = nullPanel.getBounds().x;// 得到空方格的横坐标
		int nullDir_Y = nullPanel.getBounds().y;// 得到空方格的纵坐标
		if (x1 == nullDir_X && y1 - nullDir_Y == 100)// 进行比较果满足条件则交换
			button.move("UP", 100);// 方格向上移动
		else if (x1 == nullDir_X && y1 - nullDir_Y == -100)
			button.move("DOWN", 100);// 方格向下移动
		else if (x1 - nullDir_X == 100 & y1 == nullDir_Y)
			button.move("LEFT", 100);// 方格向左移动
		else if (x1 - nullDir_X == -100 && y1 == nullDir_Y)
			button.move("RIGHT", 100);// 方格向右移动
		else
			return;
		nullPanel.setLocation(x1, y1);// 重新设置空方格的位置
		this.repaint();// 重新加载
		if (this.isFinish()) {// 进行是否完成的判断
			JOptionPane.showMessageDialog(this, "恭喜你,完成拼图");
			for (int i = 0; i < 8; i++) {// 循环撤消鼠标事件
				pane[i].removeMouseListener(this);
			}
			hasAddActionListener = false;
		}
	}
}

程序解读

  1. PanelOfImage类继承按钮类实现按钮添加图片的方格的功能。其构造方法设置每个方格的大小并设置图标。move()方法是移动指定的方格,根据传递的参数设置方格在窗口的位置来看作是移动方格。

  2. PanelOfImage类继承面板类实现鼠标监听事件接口实现面板加载方格按钮。hasAddActionListener标识判断是否添加动作事件,声明pane面板按钮数组在面板中添加方格按钮;声明nullPanel表示一个空方格,空方格上没有动作事件和图片。该类的构造方法中设置面板的布局为空,则该面板中的组件可以随意摆放,并设置面板的大小为400×400,设置空方格的方位和创建几个方格。运用双重循环创建图片图标并将图标放置在方格上,同时设置每个方格的位置,再将设置好的方格添加到面板中。

  3. isFinish()方法判断方格拼凑的图形是否与原图片相同。运用循环获得每个方格的横、纵坐标,如果拼凑的每个图片位置与加载时每个方格的位置相同,则拼凑成功。

  4. reLoadPicture()方法在选择图片时面板重新加载按钮图片面板。运用双重循环获得图片图标,再将图片图标添加到按钮面板(每个方格)。

  5. breakRank()方法是将加载到面板中的按钮方格打乱排列。运用第一个方格距左上角近时进行循环,获得空方格的横、纵坐标。再运用Math类的random()方法随机产生一个0~3之间的整数。如果整数是0,则将空方格左移动,与左侧的方格互换位置,左侧的方格右移动;如果整数是1,则将空方格右移动与右侧的方格互换位置,右侧的方格左移动;如果整数是2,则将空方格向上移动,与上侧的方格互换位置,上侧的方格向下移动;如果整数是3,则将空方格向下移动,与下侧的方格互换位置,下侧的方格向上移动。判断方格是否添加动作事件,如果没有,则运用循环对每个方格添加动作事件监听器。

  6. test()方法检测每个方格是否在指定的面板范围内移动。如果方格的横坐标或纵坐标超出面板的范围则返回假,否则为真。

  7. PanelOfImage类实现MouseListener()接口,必须实现它的5个方法:mouseClicked()、mouseEntered()、mouseExited()、mouseReleased()和mousePressed()。当鼠标按下时触发mousePressed()方法,该方法根据鼠标事件获得单击的方格按钮的横、纵坐标以及空方格的横、纵坐标。如果单击的方格与空方格的横坐标相同,单击方格的纵坐标比空方格的纵坐标大100,则单击的方格位于空方格的下方,单击的方格要向上移动;如果单击的方格与空方格的横坐标相同,单击方格的纵坐标比空方格的纵坐标小100,则单击的方格位于空方格的上方,单击的方格要向下移动;如果单击的方格与空方格纵坐标相同,单击方格的横坐标比空方格的横坐标大100,则单击的方格位于空方格的右方,单击的方格要向左移动;如果单击的方格与空方格的纵坐标相同,单击方格的横坐标比空方格的横坐标小100,则单击的方格位于空方格的左方,单击的方格要向右移动。如果拼凑图形完成,调用isFinish()方法判断拼凑的图形与原加载的图形是否一致,如果一致则弹出对话框提示成功拼凑图形。再运用循环移除每个方格的鼠标监听器。

  8. ImagePieceTogether类继承JFrame类实现ActionListener接口,实现接口必须实现其actionPerformed()方法。在该类的构造方法中创建容器面板,创建南侧面板并在面板中添加开始按钮、查看按钮以及选择按钮并设置面板的背景为红色,每个按钮都添加事件监听器,创建查看面板并设置其布局为空,这样组件可以在其面板中随意摆放。创建图片面板放在容器面板的中间位置。设置窗口的标题、位置、大小以及可视化等。

  9. ImagePieceTogether类的actionPerformed()方法是处理单击按钮触发的事件。根据事件的getSource()方法获得单击的按钮。如果单击“开始”按钮,则调用PanelOfImage类的breakRank()打乱图片的方法。如果单击“查看”按钮,则判断按钮的标签,如果标签为“查看”则移除图片面板,添加查看标签,对容器面板进行重绘以及重新设置标签为“返回”;如果标签不是“查看”,则移除查看面板添加图片面板,对容器面板进行重绘以及重新设置标签为“查看”。如果单击“选择”按钮,创建选择器,并弹出对话框对图片进行选择。如果单击“确定”按钮则获得选择器中选择的图片的编号,根据编号获得指定的图片,再根据图片创建图标标签,查看面板添加图标标签并进行重绘来显示图片。


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
  • 全部评论(1)
资料加载中...
已关注 , 取消