import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.border.BevelBorder;
public class HitMouses extends JFrame implements ActionListener, MouseListener {
private static final long serialVersionUID = 1L;// 唯一的可串行化版本的标识
private String dir = "./images/";// 找到当前文件夹下的images文件
private Timer timer;// 用来显示地鼠
private Random uRandom;// 与Math.random()的方法相同
private JLabel jLabelMouse, timesShowLabel, timesHitLabel, gradeLabel;
private int timesShow = 0, timesHit = 0, grade = 1, delay = 1000;
private Font font = new Font("幼圆", Font.BOLD, 20);
private boolean isHit;// 判断是否可以击打地鼠,为true时不可以击打,且不能增加击打次数
private JMenu menuGame, menuHelp;
private JMenuItem menuItemSatrt, menuItemEnd, menuItemHelp;
public HitMouses() {
// 设置框架
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(200, 100, 438, 375);// 这个大小会变,要注意最后一次调整.这个大小要根据背景图片定,图片大小为(433,346).
// this.setResizable(false);
// 设置背景
this.mySetBackground();
// 设置地鼠图片
this.mySetJLabelMouse();
// 设置光标图片
this.mySetCursorImage(1);// 图片应该显示成捶打的状态
this.addMouseListener(this);// 使整个图片都可以点击
// 设置标题
this.setTitle("打地鼠");
// new 对象
timer = new Timer(1000, new myActionListener());
uRandom = new Random();
// this.getContentPane().setLayout(null);//
// 不加这句,地鼠的位置就会乱;不去掉,就无法显示面板,当然这是老鼠又可以正常显示了
// 加块面板
addJPanel();
// 加菜单条
addMenu();
// 显示地鼠
timer.start();
// 设置显示
this.setVisible(true);
}
private void addMenu() {
// new 对象
JMenuBar menuBar = new JMenuBar();
menuGame = new JMenu("Game");
menuHelp = new JMenu("Help");
menuItemSatrt = new JMenuItem("Start");
menuItemEnd = new JMenuItem("End");
menuItemHelp = new JMenuItem("About");
// 给菜单项加监听
menuItemSatrt.addActionListener(this);
menuItemEnd.addActionListener(this);
menuItemHelp.addActionListener(this);
// menuGame加菜单项
menuGame.add(menuItemSatrt);
menuGame.addSeparator();
menuGame.add(menuItemEnd);
// menuHelp加菜单项
menuHelp.add(menuItemHelp);
// 工具条加菜单
menuBar.add(menuGame);
menuBar.add(menuHelp);
// 加菜单条
this.setJMenuBar(menuBar);
}
private void addJPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));// 面板加图片最好设置边框,API提示
panel.setPreferredSize(new Dimension(438, 375));// 设置首选大小
panel.setOpaque(false);// 设置是否不透明,这里设置为透明
// 出现次数
timesShowLabel = new JLabel("0",
new ImageIcon(dir + "chuxiancishu.png"), SwingConstants.CENTER);
timesShowLabel.setFont(font);
timesShowLabel.setSize(146, 40);
// 当前等级
gradeLabel = new JLabel("1", new ImageIcon(dir + "dangqiandengji.png"),
SwingConstants.CENTER);
gradeLabel.setFont(font);
gradeLabel.setSize(146, 40);
// 打中次数
timesHitLabel = new JLabel("0",
new ImageIcon(dir + "dazhongcishu.png"), SwingConstants.CENTER);
timesHitLabel.setFont(font);
timesHitLabel.setSize(146, 40);
// 面板上加标签
panel.add(timesShowLabel);
panel.add(timesHitLabel);
panel.add(gradeLabel);
// 加面板
this.getContentPane().add(panel);
}
private void mySetCursorImage(int i) {
// 传进一个i分别是1或2
Toolkit tool = Toolkit.getDefaultToolkit();// 利用工厂方法,获得一个ToolKit对象
Image image = tool.createImage(dir + "chui" + i + ".png");// 可以用子类BufferedImage
Cursor cursor = tool.createCustomCursor(image, new Point(10, 10), "lq");
// 名字可以随便给一个
// hotSpot 热点范围
this.setCursor(cursor);
}
private void mySetJLabelMouse() {
// 与mySetMouseImage(1)不同的是,这个有监听,最好不要重复写
ImageIcon image = new ImageIcon(dir + "dishu1.png");
jLabelMouse = new JLabel(image);
// 设置位置,可使图片显示在不同的位置
jLabelMouse.setBounds(56, 63, 80, 80);// 图片大小(59,69);
this.getContentPane().add(jLabelMouse);
jLabelMouse.setVisible(false);
jLabelMouse.addMouseListener(this);
}
private void mySetMouseImage(int i) {
// 与mySetJLabelMouse()不同的是,这个只用来转换图片
ImageIcon image = new ImageIcon(dir + "dishu" + i + ".png");
jLabelMouse.setIcon(image);
jLabelMouse.setVisible(true);
}
private void mySetBackground() {
((JPanel) this.getContentPane()).setOpaque(false);// 转换成子类,调用setOpaque(不透明的)//允许其底层像素透视出来
Icon image = new ImageIcon(dir + "beijing.jpg");
JLabel backLabel = new JLabel(image);
backLabel.setBounds(0, 0, image.getIconWidth(), image.getIconHeight());// 必须要设置大小,不然无法显示
// this.getLayeredPane().add(backLabel);// 无法显示图片
this.getLayeredPane().add(backLabel, new Integer(Integer.MIN_VALUE));
}
public static void main(String[] args) {
new HitMouses();
}
private class myActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// 产生一个随机数使地鼠不断出现,这个技术实际上就是图片的分层显示,只要把这个解决,图片类游戏基本学会
// 方法:把图片放到JLabel中,然后设置位置显示,就这么简单
int ran = uRandom.nextInt(9);// 这个方法比Math.random()的方法好用一些//属于[0,9)范围内
// 设置老鼠位置
switch (ran) {
case 0:
jLabelMouse.setLocation(56, 38);// 63-25= 38
break;
case 1:
jLabelMouse.setLocation(322, 179);// 204 -25 = 179
break;
case 2:
jLabelMouse.setLocation(185, 179);
break;
case 3:
jLabelMouse.setLocation(48, 178);
break;
case 4:
jLabelMouse.setLocation(298, 108);// 133 -25 = 108
break;
case 5:
jLabelMouse.setLocation(162, 108);
break;
case 6:
jLabelMouse.setLocation(22, 108);
break;
case 7:
jLabelMouse.setLocation(311, 38);
break;
case 8:
jLabelMouse.setLocation(186, 38);
break;
}
// 每次老鼠出来都是没有打中的样子
mySetMouseImage(1);
// 游戏规则:
// 每击中7次就升一次级;
// 如果满四级就代表游戏胜利;
// 老鼠出现15次就表示游戏失败。
if (mouseShowTimes() >= 15) {// 游戏失败处理.
end();
int yes = JOptionPane.showConfirmDialog(HitMouses.this,
"很遗憾,你输了。\n是否要重新开始?", "失败", JOptionPane.YES_NO_OPTION);
if (yes == JOptionPane.YES_NO_OPTION) {
start();
}
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == menuItemSatrt) {
start();
return;
}
if (e.getSource() == menuItemEnd) {
if (JOptionPane.showConfirmDialog(this, "你确定要退出吗?") == 0) {
System.exit(0);
}
return;
}
if (e.getSource() == menuItemHelp) {
JDialog dialog = new JDialog(this, "游戏规则:");
dialog.setBounds(this.getX()+20, this.getY()+20, 250, 160);
dialog.setLayout(new GridLayout(4, 1));
dialog.add(new JLabel("游戏规则"));
dialog.add(new JLabel("1)每击中7次就升一次级;"));
dialog.add(new JLabel("2)如果满四级就代表游戏胜利;"));
dialog.add(new JLabel("3)老鼠出现15次就表示游戏失败。"));
dialog.setVisible(true);
}
}
public void end() {
timer.stop();
}
public void start() {
mySetMouseImage(1);
timesShow = 0;
timesHit = 0;
grade = 1;
delay = 1000;
timesShowLabel.setText("" + timesShow);
timesHitLabel.setText("" + timesHit);
gradeLabel.setText("" + grade);
timer.start();
setDelay(0);
}
public int mouseShowTimes() {
timesShow++;
timesShowLabel.setText("" + timesShow);
// 老鼠每次出现都定义为未击打状态
isHit = false;
return timesShow;
}
public int mouseHitTimes() {
timesHit++;
timesHitLabel.setText("" + timesHit);
return timesHit;
}
public int mouseGrade() {
grade++;
gradeLabel.setText("" + grade);
return grade;
}
public void setDelay(int d) {
if (timer != null) {
delay += d;
if (delay < 290) {// 4*180 = 720
delay = 1000;
}
timer.setDelay(delay);
}
}
// 鼠标监听可以写成内部类,但是这里有特殊需要,比如:点击图片的任意位置都可以是光标变化
@Override
public void mouseClicked(MouseEvent e) {// 没用
}
@Override
public void mousePressed(MouseEvent e) {// 目标
mySetCursorImage(2);
if (e.getSource() == jLabelMouse && !isHit) {
// 老鼠被打中,那么再下次老鼠没有出来之前,不可再次击打老鼠,且不可增加击打次数
isHit = true;
// 光标显示击打状态
mySetMouseImage(2);
// 升级
if (mouseHitTimes() >= 7) {// 击中7次时
setDelay(-180);
// 游戏胜利判断
if (mouseGrade() >= 5) {
end();
// 游戏结束,老鼠不可显示
jLabelMouse.setVisible(false);
int a = JOptionPane.showConfirmDialog(this, "您打通关了,要重新来吗?",
"恭喜!!!", JOptionPane.YES_NO_OPTION);
if (a == JOptionPane.YES_OPTION) {
start();
}
}
// 初始化老鼠出现次数和击打次数
timesShow = -1;
timesHit = -1;
mouseShowTimes();
mouseHitTimes();
}
}
}
@Override
public void mouseReleased(MouseEvent e) {// 目标
mySetCursorImage(1);
}
@Override
public void mouseEntered(MouseEvent e) {// 没用
}
@Override
public void mouseExited(MouseEvent e) {// 没用
}
}