学习几个小游戏来打发时间,这个图片配对游戏其实非常简单,就是一个鼠标移动点击游戏,运行图如下:
就是将图片移到相应的位置然后位置就会变成绿色,意味着成功。但是看完代码,我个人觉得还是有些地方的逻辑并不严谨。
下面我们开始解析代码来说明哪里不严谨:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
public class PictureMatchingFrame extends JFrame implements MouseListener,
MouseMotionListener {
private JLabel img[] = new JLabel[3];// 显示图标的标签
private JLabel targets[] = new JLabel[3];// 窗体下面显示文字的标签
private Point pressPoint; // 鼠标按下时的起始坐标
public static void main(String args[]) {
PictureMatchingFrame frame = new PictureMatchingFrame(); // 创建本类对象,显式GUI
frame.setVisible(true); // 设置窗体为可视状态
}
public PictureMatchingFrame() {
super();
getContentPane().setLayout(new BorderLayout());
setBounds(100, 100, 364, 312);
setTitle("图片配对游戏");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel imagePanel = new JPanel();
imagePanel.setLayout(null);
imagePanel.setOpaque(false);
setGlassPane(imagePanel);
getGlassPane().setVisible(true);
ImageIcon icon[] = new ImageIcon[3];
icon[0] = new ImageIcon(getClass().getResource("screen.png"));
icon[1] = new ImageIcon(getClass().getResource("clothing.png"));
icon[2] = new ImageIcon(getClass().getResource("bike.png"));
final JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 5));
getContentPane().add(bottomPanel, BorderLayout.SOUTH);
for (int i = 0; i < 3; i++) {
img[i] = new JLabel(icon[i]); // 创建图像标签
img[i].setSize(50, 50); // 设置标签大小
img[i].setBorder(new LineBorder(Color.GRAY)); // 设置线性边框
int x = (int) (Math.random() * (getWidth() - 50)); // 随机生成X坐标
int y = (int) (Math.random() * (getHeight() - 150));// 随机生成Y坐标
img[i].setLocation(x, y); // 设置随机坐标
img[i].addMouseListener(this); // 为每个图像标签添加鼠标事件监听器
img[i].addMouseMotionListener(this);
imagePanel.add(img[i]); // 添加图像标签到图像面板
targets[i] = new JLabel(); // 创建匹配位置标签
targets[i].setOpaque(true); // 使标签不透明,以设置背景色
targets[i].setBackground(Color.ORANGE); // 设置标签背景色
targets[i].setHorizontalTextPosition(SwingConstants.CENTER); // 设置文本与图像水平居中
targets[i].setVerticalTextPosition(SwingConstants.BOTTOM); // 设置文本显示在图像下方
targets[i].setPreferredSize(new Dimension(80, 80)); // 设置标签首先大小
targets[i].setHorizontalAlignment(SwingConstants.CENTER); // 文字居中对齐
bottomPanel.add(targets[i]); // 添加标签到底部面板
}
targets[0].setText("显示器"); // 设置匹配位置的文本
targets[1].setText("衣服");
targets[2].setText("自行车");
}
public void mouseClicked(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint(); // 保存拖放图片标签时的起始坐标
}
public void mouseReleased(MouseEvent e) {
if (checkPosition()) { // 如果配对正确
getGlassPane().setVisible(false);
for (int i = 0; i < 3; i++) { // 遍历所有匹配位置的标签
targets[i].setText("匹配成功"); // 设置正确提示
targets[i].setIcon(img[i].getIcon()); // 设置匹配的图标
}
}
}
/**
* 鼠标拖动控件时的事件处理方法
*/
public void mouseDragged(MouseEvent e) {
JLabel source = (JLabel) e.getSource(); // 获取事件源控件
Point imgPoint = source.getLocation(); // 获取控件坐标
Point point = e.getPoint(); // 获取鼠标坐标
source.setLocation(imgPoint.x + point.x - pressPoint.x, imgPoint.y
+ point.y - pressPoint.y); // 设置控件新坐标
}
private boolean checkPosition() {// 检查配对是否正确
boolean result = true;
for (int i = 0; i < 3; i++) {
Point location = img[i].getLocationOnScreen(); // 获取每个图像标签的位置
Point seat = targets[i].getLocationOnScreen(); // 获取每个对应位置的坐标
targets[i].setBackground(Color.GREEN); // 设置匹配后的颜色
//System.out.println(location.x+" "+location.y);
// 如果配对错误
if (location.x < seat.x || location.y < seat.y
|| location.x > seat.x + 80 || location.y > seat.y + 80) {
targets[i].setBackground(Color.ORANGE); // 回复对应位置的颜色
result = false; // 检测结果为false
}
}
return result; // 返回检测结果
}
}
看完代码,在原有的基础上,不知大家发现没,它的关键方法是:
private boolean checkPosition() {// 检查配对是否正确
boolean result = true;
for (int i = 0; i < 3; i++) {
Point location = img[i].getLocationOnScreen(); // 获取每个图像标签的位置
Point seat = targets[i].getLocationOnScreen(); // 获取每个对应位置的坐标
targets[i].setBackground(Color.GREEN); // 设置匹配后的颜色
//System.out.println(location.x+" "+location.y);
// 如果配对错误
if (location.x < seat.x || location.y < seat.y
|| location.x > seat.x + 80 || location.y > seat.y + 80) {
targets[i].setBackground(Color.ORANGE); // 回复对应位置的颜色
result = false; // 检测结果为false
}
}
return result; // 返回检测结果
}
这个方法的关键地方是:
if (location.x < seat.x || location.y < seat.y
|| location.x > seat.x + 80 || location.y > seat.y + 80) {
targets[i].setBackground(Color.ORANGE); // 回复对应位置的颜色
result = false; // 检测结果为false
}
从上面代码我们可以看出,它是以图片的左上角点和字的区域左上角点的相对位置来判断是否拖到相应位置,于是就有了下面bug:
上面的情况从常理来看它的大部分是在衣服上的,但是显示器显示为绿色,很明显不严谨。
OK! 进行到这一步我们就要进行改进了,俗称修复bug,哈哈。
于是我们就要进行思考解决方案了:
方案一:计算重合面积,面积最大者即为目标位置。这个方案符合常理,但是要如何实现呢?我们遇到的问题如下:
如何计算这个重合面积以及如何判断那个大,以及判断重合多少才算配对成功?
方案二:只有全在里面才算配对成功,否则配对不成功。相比之下,方案二更简洁,也比较符合我这样的强迫症患者哈哈。
因为我是强迫症患者,所以我选择方案二:
改进后的代码如下:
private boolean checkPosition() {// 检查配对是否正确
boolean result = true;
for (int i = 0; i < 3; i++) {
Point location = img[i].getLocationOnScreen(); // 获取每个图像标签的位置
Point seat = targets[i].getLocationOnScreen(); // 获取每个对应位置的坐标
int x1=location.x,y1=location.y;
int x2=x1+50,y2=y1;
int x3=x1,y3=y1+50;
int x4=x1+50,y4=y1+50;
if (x1 >=seat.x && y1 >= seat.y
&& x2 <= seat.x + 80 && y2 <= seat.y + 80 && x3 >= seat.x
&&y3<=seat.y+80 && x4<=seat.x+80&&y4<=seat.y+80 ) {
targets[i].setBackground(Color.GREEN); // 设置匹配后的颜色
result = true; // 检测结果为false
}else{
targets[i].setBackground(Color.ORANGE); // 回复对应位置的颜色
result=false;
}
return result; // 返回检测结果
}
运行效果良好哈哈: