通过Java awt 界面上的知识编写的扫雷游戏

代码中有详细的注解

package com.langsin.saolei;

import java.awt.Color;

import java.awt.Font;

import java.awt.Frame;

import java.awt.Graphics;

import java.awt.GridLayout;

import java.awt.Image;

import java.awt.Insets;

import java.awt.Label;

import java.awt.Menu;

import java.awt.MenuBar;

import java.awt.MenuItem;

import java.awt.MenuShortcut;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.KeyEvent;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.awt.image.BufferedImage;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import javax.imageio.ImageIO;

import javax.swing.ImageIcon;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

public class Saolei extends Frame implements ActionListener {

// 先定义横向的按钮的个数和纵向的按钮的个

private static int WITH = 10;

private static int LENG = 10;

// 定义地雷的个数

private static int Mines_Count = 10;

// 定义旗帜的个数

private static int Red_Count = 10;

// 定义一个random类

private static Random random = new Random();

// 定义一个二维数组

private static Bomb[][] jb = new Bomb[WITH][LENG];

// 判断是否结束

private boolean flag = false;

// 判断是否成功 默认是没有成功

private boolean sucess = false;

// 用集合暂存sucess.txt中的内容

private List list = new ArrayList();

// 用集合暂存游戏时间

private List listtime = new ArrayList();

StringBuffer buffer = new StringBuffer();

// 定义一个面板成员变量

private JPanel jp;

// 记录时间的线程

private Runnable runnable;

// 已用时间

private int usedTime = 0;

// 定义两个标签 时间和旗帜

private Label time, redFlag;

/*

* 检测某点周围是否有雷,周围点的坐标可由该数组计算得到

*/

private int[][] mv = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 }, { 1, 1 },

{ -1, -1 }, { 1, -1 }, { -1, 1 } };

// 通过构造器初始化

public Saolei() throws Exception {

super("扫雷");

// 绝对布局管理器

this.setLayout(null);

// 设置图标

this.setIconImage(ImageIO.read(new File("./image/图标.jpg")));

// 设置大小

this.setBounds(100, 100, 500, 500);

this.addWindowListener(new WindowAdapter() {

@Override

public void windowClosing(WindowEvent e) {

System.exit(0);

}

});

setMenu();

intMine();

intBottom();

this.setResizable(false);

this.setVisible(true);

}

// 设置初始化菜单

public void setMenu() {

// 菜单条

MenuBar menbar = new MenuBar();

// 菜单项 游戏

Menu game = new Menu("游戏(G)");

// 菜单项游戏的组件 新游戏

MenuItem newgame = new MenuItem("新游戏");

// 游戏从新开始

newgame.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

// 调用重新开始游戏的方法

resetGame();

}

});

game.add(newgame);

// 菜单项游戏的组件 更改外观

MenuItem change = new MenuItem("更改外观");

change.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

for (int i = 0; i < WITH; i++) {

for (int j = 0; j < LENG; j++) {

if (!jb[i][j].isIsclicked() && jb[i][j].isEnabled()) {

jb[i][j].setBackground(Color.BLUE);

} else {

jb[i][j].setBackground(Color.WHITE);

}

}

}

}

});

game.add(change);

// 加一条横线

// game.addSeparator();

game.add(new MenuItem("-"));

// 菜单项游戏的组件 退出

MenuItem exit = new MenuItem("退出",

new MenuShortcut(KeyEvent.VK_A, true));

exit.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

// TODO Auto-generated method stub

System.exit(0);

}

});

game.add(exit);

menbar.add(game);

// 菜单项 帮助

Menu Tj = new Menu("统计(T)");

// 菜单项游戏的组件 统计信息

MenuItem record = new MenuItem("查看统计信息");

// 将游戏的成败和时间记录两个txt文本中

record.addActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

try {

Tongji();

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

});

Tj.add(record);

menbar.add(Tj);

// 添加菜单条

this.setMenuBar(menbar);

}

// 初始化底部

private void intBottom() {

// 创建两个label 一个是时间 一个是计时

Label lab1 = new Label("时间");

lab1.setFont(new Font("宋体", Font.BOLD, 15));

lab1.setForeground(Color.BLUE);

lab1.setBounds(80, 430, 35, 35);

this.add(lab1);

time = new Label("0");

time.setFont(new Font("宋体", Font.PLAIN, 15));

time.setBounds(140, 435, 50, 25);

this.add(time);

// 一个是标记 小红旗的个数

Label lab2 = new Label("旗帜");

lab2.setFont(new Font("宋体", Font.BOLD, 15));

lab2.setForeground(Color.BLUE);

lab2.setBounds(300, 430, 35, 35);

this.add(lab2);

redFlag = new Label(" 10");

redFlag.setFont(new Font("宋体", Font.PLAIN, 15));

redFlag.setBounds(350, 435, 50, 25);

this.add(redFlag);

// 通过接口来实现

runnable = new Runnable() {

public void run() {

while (true) {

// 是否结束

if (flag) {

break;

}

try {

// 睡眠1s

Thread.sleep(1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

// 已用时间+1

usedTime++;

time.setText(String.valueOf(usedTime));

}

}

};

// 开始线程

new Thread(runnable).start();

}

// 初始化雷区(用按钮来充当地雷 用面板在面板上添加按钮)

private void intMine() {

// 将按钮放在面板上

jp = new JPanel();

// 面板的布局管理器为网格布局管理器

jp.setLayout(new GridLayout(WITH, LENG, 0, 0));

// 设置面板的位置

jp.setBounds(75, 70, 350, 350);

makeMines(true);

this.add(jp);

}

// 随机布置雷区 重置雷区

private void makeMines(boolean newFlag) {

// 在面板上面放按钮 并设置初始按钮属性

for (int i = 0; i < LENG; i++) {

for (int j = 0; j < WITH; j++) {

if (newFlag) {

// 记录下位置

jb[i][j] = new Bomb(i, j);

jp.add(jb[i][j]);

// 设置按钮和标签之间的空白 数字所在按钮的位置

jb[i][j].setMargin(new Insets(0, 0, 0, 0));

jb[i][j].addActionListener(this);

// 鼠标点击事件 鼠标右击

jb[i][j].addMouseListener(new MouseAdapter() {

@Override

public void mouseClicked(MouseEvent e) {

Object obj = e.getSource();

// e.isMetaDown() 检测鼠标右键单击

if (e.isMetaDown() && obj instanceof Bomb) {

// 强制类型转换

Bomb bomb = (Bomb) obj;

// 旗帜的个数大于等于0

if (bomb.isEnabled() && Red_Count >= 0) {

// 定义一个数字 来判定状态

// 右击点一下 变为1 红旗状态 两下变为2 ?号状态

int num = (bomb.getBombflag() + 1) % 3;

switch (num) {

case 0:

// 初始状态

bomb.setIcon(null);

break;

case 1:

Red_Count--;

// 缓冲图片对象

BufferedImage bf1 = new BufferedImage(

35, 35,

BufferedImage.TYPE_INT_RGB);

// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改

Graphics grap = bf1.getGraphics();

// 先读到这幅图片

Image image;

try {

image = ImageIO.read(new File(

"./image/红旗.jpg"));

// 然后通过画笔对象来改变它,将这幅图片进行缩放

grap.drawImage(image, 0, 0, 35, 35,

null);

bomb.setIcon(new ImageIcon(bf1));

} catch (IOException e2) {

// TODO Auto-generated catch block

e2.printStackTrace();

}

break;

case 2:

Red_Count++;

// 缓冲图片对象

BufferedImage bf2 = new BufferedImage(

35, 35,

BufferedImage.TYPE_INT_RGB);

// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改

Graphics grap2 = bf2.getGraphics();

// 先读到这幅图片

Image image2;

try {

// 然后通过画笔对象来改变它,将这幅图片进行缩放

image2 = ImageIO.read(new File(

"./image/问号.jpg"));

grap2.drawImage(image2, 0, 0, 35,

35, null);

bomb.setIcon(new ImageIcon(bf2));

} catch (IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

break;

default:

break;

}

redFlag.setText(String.valueOf(Red_Count));

// 改变状态

bomb.setBombflag(num);

try {

checkSuccess();

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

}

}

});

} else {

jb[i][j].setIcon(null);

jb[i][j].setEnabled(true);

// 默认为都没有点击

jb[i][j].setIsclicked(false);

jb[i][j].setText("");

// 默认是无雷

jb[i][j].setBomb(false);

// 默认初始状态值为0

jb[i][j].setBombflag(0);

}

}

}

// 布雷的个数

int i = 0;

// 定义坐标

int x, y;

while (i < 10) {

x = random.nextInt(WITH);

y = random.nextInt(LENG);

// 判断这个地方是否有雷 默认没有

if (!jb[x][y].isBomb()) {

// 设置为有雷

jb[x][y].setBomb(true);

// 查看是否有重复的

// 查看坐标位置 其中y对应的是列 x对应的是行 从0-9

System.out.println(x + " " + y);

i++;

}

}

}

// 通过点击事件来判断游戏的进展

// 点击事件

@Override

public void actionPerformed(ActionEvent e) {

Object obj = e.getSource();

if (obj instanceof Bomb) {

Bomb bs = (Bomb) obj;

// 如果得到的状态是1 即红旗 结束点击事件

if (bs.getBombflag() == 1) {

return;

}

// 如果得到的状态是2 即“?”

else if (bs.getBombflag() == 2) {

// 点击一下将问号去除

bs.setIsclicked(true);

bs.setIcon(null);

}

// 如果点到的是雷

if (bs.isBomb()) {

// 缓冲图片对象

BufferedImage bf1 = new BufferedImage(35, 35,

BufferedImage.TYPE_INT_RGB);

// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改

Graphics grap = bf1.getGraphics();

// 先读到这幅图片

Image image;

try {

image = ImageIO.read(new File("./image/地雷.png"));

// 然后通过画笔对象来改变它,将这幅图片进行缩放

grap.drawImage(image, 0, 0, 35, 35, null);

// 将图片设置为雷

bs.setIcon(new ImageIcon(bf1));

} catch (IOException e2) {

// TODO Auto-generated catch block

e2.printStackTrace();

}

// 游戏结束

flag = true;

// 显示所有的雷

try {

showMine();

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

// 弹出一个窗口对话框显示游戏结束 结束点击事件

JOptionPane.showMessageDialog(this, "扫雷失败!");

return;

}

// 没有点到雷时

// 通过算法判断是否有雷 来判断周围雷的情况

judge(bs.getNum_x(), bs.getNum_y());

}

}

// 重新开始游戏

private void resetGame() {

flag = true;

Red_Count = 10;

time.setText("0");

usedTime = 0;

redFlag.setText("10");

makeMines(false);

// 将游戏外观设为初始

for (int i = 0; i < WITH; i++) {

for (int j = 0; j < LENG; j++) {

jb[i][j].setBackground(null);

}

}

try {

Thread.sleep(1000);

} catch (InterruptedException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

new Thread(runnable).start();

flag = false;

}

// 如果点到雷,游戏结束显示所有雷

// 显示所有雷的方法

private void showMine() throws Exception {

for (int i = 0; i < WITH; i++) {

for (int j = 0; j < LENG; j++) {

if (jb[i][j].isBomb()) {

// 缓冲图片对象

BufferedImage bf1 = new BufferedImage(35, 35,

BufferedImage.TYPE_INT_RGB);

// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改

Graphics grap = bf1.getGraphics();

// 先读到这幅图片

Image image = ImageIO.read(new File("./image/地雷.png"));

// 然后通过画笔对象来改变它,将这幅图片进行缩放

grap.drawImage(image, 0, 0, 35, 35, null);

jb[i][j].setIcon(new ImageIcon(bf1));

}

}

}

}

// 判断是否成功

private void checkSuccess() throws Exception {

int count = 0;

for (int i = 0; i < LENG; i++) {

for (int j = 0; j < WITH; j++) {

// 如果是雷 并且这个地方有红旗

if (jb[i][j].isBomb() && jb[i][j].getBombflag() == 1) {

// 进行累加

count++;

}

}

}

if (count == Mines_Count) {

flag = true;

JOptionPane.showMessageDialog(this, "恭喜你,胜利了!");

sucess = true;

String tm = time.getText();

listtime.add(tm);

writesucess(sucess);

}

}

// 判断周围是否有雷

private void judge(int x, int y) {

// 设置(x,y)这个位置已经点击 得到这个位置

jb[x][y].setIsclicked(true);

// 点击了以后将背景设置为白色

jb[x][y].setBackground(Color.WHITE);

// 点过的设置为不可点击 点击过设置为不可用

jb[x][y].setEnabled(false);

// 设定点击的这个点的相对初始位置是(0,0) 设定初始周围雷的个数是0

int sx = 0;

int sy = 0;

int mineNumber = 0;

for (int i = 0; i < mv.length; i++) {

sx = x + mv[i][0];

sy = y + mv[i][1];

// 保证所有的坐标点都在面板上 判断那些没有被点击过的按钮

if (sx >= 0 && sx < WITH && sy >= 0 && sy < LENG) {

if (jb[sx][sy].isBomb()) {

// 如果是雷的话

// 显示的数字累加 得到(x,y)这个位置周围雷的个数

mineNumber++;

}

}

}

// 通过递归来实现

if (mineNumber == 0) {

for (int i = 0; i < mv.length; i++) {

sx = x + mv[i][0];

sy = y + mv[i][1];

// 保证所有的坐标都对应一个按钮

if (sx >= 0 && sx < LENG && sy >= 0 && sy < LENG

&& !jb[sx][sy].isIsclicked()) {

judge(sx, sy);

}

}

} else {

jb[x][y].setFont(new Font("宋体", Font.BOLD, 12));

jb[x][y].setText(String.valueOf(mineNumber));

}

}

// 只有成功了才写

// 写一个方法将成功记录写到sucess.txt 文件中

private void writesucess(boolean sucess) throws Exception {

int snum = 0;

// 如果list中没有元素

readsucess();

if (list.isEmpty()) {

PrintWriter pw = new PrintWriter(new File("./sucess.txt"));

pw.println("游戏结果\t游戏时间");

buffer.append("游戏成功" + "\t" + listtime.get(snum));

pw.println(buffer.toString());

pw.close();

snum++;

} else {

PrintWriter pw = new PrintWriter(new File("./sucess.txt"));

for (int i = 0; i < list.size(); i++) {

pw.println(list.get(i));

}

buffer.append("游戏成功" + "\t" + listtime.get(snum));

pw.println(buffer.toString());

pw.close();

snum++;

}

}

private void readsucess() throws Exception {

BufferedReader br = new BufferedReader(new FileReader("./sucess.txt"));

String line = null;

while ((line = br.readLine()) != null) {

list.add(line);

}

br.close();

}

// 建立一个新的窗口

private void Tongji() throws Exception {

final Frame frame = new Frame("统计信息");

frame.setBounds(100, 100, 300, 300);

TextArea ta = new TextArea();

ta.setFont(new Font("宋体", Font.BOLD, 15));

ta.setForeground(Color.BLUE);

BufferedReader bf = new BufferedReader(new FileReader(new File(

"./sucess.txt")));

String line = null;

StringBuffer buf = new StringBuffer();

while ((line = bf.readLine()) != null) {

buf.append(line + "\n");

}

ta.setText(buf.toString());

bf.close();

frame.add(ta);

frame.addWindowListener(new WindowAdapter() {

@Override

public void windowClosing(WindowEvent e) {

frame.dispose();

}

});

frame.setResizable(false);

frame.setVisible(true);

}

// 程序执行

public static void main(String[] args) throws Exception {

new Saolei();

}

}

java awt 初始化_Java awt项目开发相关推荐

  1. 【源码+教程】Java桌球游戏_Java初级项目_Java练手项目_Java项目实战_Java游戏开发

    今天分享的Java开源游戏项目是桌球游戏,初学者也可以用来练习喔~课程详细讲解了一个桌球游戏的编写思路和流程,即使你刚学Java没多久,也可以跟随该教程视频完成属于你自己的桌球游戏!同时,还可以加深和 ...

  2. import java.awt 无法_java awt教程import java.awt.*

    java awt教程import java.awt.* java.awt.* 这里的java是包名,包对应的就是你磁盘当中的目录,你可以看成文件夹,awt是这个包当中的子包, 连起来也就是这个java ...

  3. java atm模拟系统_Java RPC模式开发一个银行atm模拟系统

    采用rpc模式开发一个银行atm模拟系统. 系统主要提供一个服务Card,该服务接口可以提供登录.查询.取钱.存钱等功能.服务接口的设计和实现自定义. Atm客户端功能需求: 1.ATM可以实现用户登 ...

  4. java程序初始化_Java程序初始化顺序

    今天在课上复习了Java的初始化顺序,一直有点疑惑,搞不明白,所以打算写下来,记录一下. 先说一下Java程序初始化的顺序:父类静态变量>父类静态代码块>子类静态变量>子类静态代码块 ...

  5. java.awt包_java.awt包介绍

    组件, Component类是所有AWT组件的根. 用户与组件交互操作时,一些组件会激发事件, AWTEvent类及其子类用于表达AWT组件能够激发的事件. 容器是一个可以含有组件和其他容器的组件, ...

  6. java.awt包_java.awt包 简介

    java.awt有创建用户接口.绘图和图像的所有类.用户接口对象,例如按钮或滚动条, 在AWT(Abstrat Window Toolkit)中被称为组件, Component类是所有AWT组件的根. ...

  7. java抗锯齿_java.awt.Graphics2D抗锯齿(字体平滑)处理

    由于项目要在图片中动态加入文字,没想到字体有毛边,找了N多文章没找到解决方法,最后用英文关键字在google上找到了,唉,为什么大家对这些都不关心呢? Java 2D - smooth text fo ...

  8. java textfield类方法_java.awt.TextField类

    java.awt.TextField是一个文本框组件 1.构造方法 TextField():创建一个默认长度为一个机器字符长的文本框 TextField(int n):创建一个指定长度为n个机器字符长 ...

  9. java awt编程_java awt编程

    展开全部 import java.awt.Frame; import java.awt.TextField; import java.awt.event.ActionEvent; import jav ...

最新文章

  1. 【黑客浅析】像黑客一样思考
  2. 华为mate x2什么时候更新鸿蒙系统,华为Mate X2真机发布,今年四月可升级鸿蒙系统...
  3. 以mips为单位衡量微型计算机的性能,2016计算机二级《MS Office》选择题专项训练...
  4. Java8学习笔记(三)--方法引入
  5. BZOJ 4610: [Wf2016]Ceiling Functi 水题
  6. 452. 用最少数量的箭引爆气球(贪心算法+思路+详解)07
  7. iOS应用横竖屏切换
  8. Linux进程共享通信 -- mmap实现
  9. 2019下半年系统集成项目管理工程师上午真题
  10. 无需埋点的移动数据分析平台GrowingIO V1.0
  11. The Python Debugger Command
  12. java字符串计数从零还是从一,java – 计数和所有字符相同的最大字符串的起始索引...
  13. js后退一直停留在当前页面或者禁止后退
  14. QQ聊天记录恢复、迁移教程(改变默认存储位置、个人文件夹保存位置)【转载】
  15. Canvas绘制六边形网格
  16. 服务器系统适合家庭电脑用吗,服务器可以用作家用电脑吗?两者有何区别?不怕噪音和耗电就可以...
  17. java程序员那些提升_Java程序员如何进行自我提升?
  18. [附源码]JAVA+ssm视频网站(程序+Lw)
  19. 怎么解决访问所有HTTPS网站显示连接不安全
  20. Android 代码混淆 R8与Proguard

热门文章

  1. ansi c标准_C/C++的起源与发展故事,我是最牛的软件编程语言,不接受反驳
  2. #ifdef __cplusplus 的用法(C语言调用c++代码)(extern “C“)
  3. python opencv cv.applyColorMap()函数(颜色映射)ColormapTypes【将Intel Realsense D435深度图的黑白图映射为彩色图】
  4. Spring的控制反转以及依赖注入,控制反转使程序具有高拓展性。
  5. Special Numbers 进制(1100)
  6. Spring @Import 注解使用详解
  7. keepalived 多个应用_Keepalived与LVS部署多个服务
  8. ipad如何连接电脑_ipad如何将电脑文件下载到本地?
  9. java程序中date类型比较大小总结
  10. Java获取近七天的数据条数,及页面实现折线图(附前后端代码)