首先感谢08年MLDN出的这个培训视频,我把代码和文档整理了一下,发布出来给需要学习Swing的朋友。

源码地址:

https://gitee.com/indexman/gobang

一、知识点准备:

JFrame:窗体

JOptionPane:对话框

MouseListener:鼠标事件

Graphics:绘制二维图像

Thread:线程类

二、五子棋游戏的功能:

  1. 在点击鼠标时,可以在相应的位置显示棋子。
  2. 可以自动判断游戏是否结束,是否黑方或白方已经胜利
  3. 对游戏时间进行设置,判断是否超出规定时间

三、游戏开发步骤

1.开发游戏界面

计算棋盘中每一条线的间距:这里用的是19X19的围棋棋盘,

总宽度为360px, 分成18份,每份是20px

2.在棋盘上的鼠标点击位置,显示一个棋子

黑子:一个实心的黑圆表示

白子:一个空心的黑圆+一个实心的白圆表示

repaint() 方法表示重新执行一次paint()方法。

3.保存之前下过的棋子

通过一个二维数组来保存之前下过的所有棋子。

4.判断游戏胜负

依据 五子棋 的基本游戏规则,判断是否有同一颜色的棋子连城5个。

完成五子棋游戏的核心算法

这里可以把核心算法总结成一个灵活的方法。

提示信息的保存

5.处理屏幕闪烁问题

使用双缓冲技术

6.实现各个按钮的功能

开始游戏:重新开始游戏

游戏设置: 设置倒计时时间

游戏说明:用来说明游戏规则和操作

认输:某一方放弃游戏,投子认负

关于:显示游戏制作者

退出:退出程序

-----------------------------------------------------分割线------------------------------------------------------

四、代码部分

1.启动类

package com.laoxu.game;

import com.laoxu.game.view.GobangFrame;
import com.laoxu.game.view.MyFrame; /**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{ GobangFrame frame = new GobangFrame();
//MyFrame myFrame = new MyFrame();
//JOptionPane
/*JOptionPane.showMessageDialog(myFrame,"我的信息");
int result = JOptionPane.showConfirmDialog(myFrame,"确定要开始游戏吗?","",0);
if(result==0){
JOptionPane.showMessageDialog(myFrame,"游戏开始");
}
if(result==1){
JOptionPane.showMessageDialog(myFrame,"游戏结束");
}
if(result==2){
JOptionPane.showMessageDialog(myFrame,"重新选择");
} String username = JOptionPane.showInputDialog("请输入你的姓名:");
System.out.println(username);
JOptionPane.showMessageDialog(myFrame,"输入的姓名为:"+username);*/
//System.out.println(System.getProperty("user.dir")+"/src/image/background.jpg"); }
}

2.五子棋类

package com.laoxu.game.view;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException; /**
* @description: 五子棋主界面
* @author: luohanye
* @create: 2019-03-21
**/
public class GobangFrame extends JFrame implements MouseListener,Runnable {
//获取当前平面分辨率,例如:1920x1080
int swidth = Toolkit.getDefaultToolkit().getScreenSize().width;
int sheight = Toolkit.getDefaultToolkit().getScreenSize().height; BufferedImage image = null;
//保存坐标值
int x = 0;
int y = 0;
//保存下过的棋子 0-没有棋子 1-黑子 2-白子
int[][] allChess = new int[19][19];
// 标识当前应该是黑子还是白子
boolean isBlack = true;
// 控制游戏是否可以玩
boolean canPlay = true;
// 保存游戏信息
String message = "黑方先行";
// 保存最多拥有多少时间(秒)
int maxTime = 0;
// 做倒计时的线程类
Thread t = new Thread(this);
// 保存黑方与白方的剩余时间
int blackTime = 0;
int whiteTime = 0;
// 保存双方剩余时间的显示信息
String blackMessage = "无限制";
String whiteMessage = "无限制"; public GobangFrame() {
//设置标题
this.setTitle("五子棋");
int width = 500, height = 500;
this.setSize(width, height); //设置窗体出现的位置
this.setLocation((swidth - width) / 2, (sheight - height) / 2);
//窗口大小不可变
this.setResizable(false);
//定义关闭动作
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//添加监听器
this.addMouseListener(this);
//窗体可见
this.setVisible(true); //加载背景图片
try {
image = ImageIO.read(new File(System.getProperty("user.dir")+"/src/image/background.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
// 启动线程
t.start();
t.suspend(); // 刷新屏幕,防止开始游戏时出现无法显示的情况.
this.repaint();
} public void paint(Graphics g) {
//双缓冲技术防止屏幕闪烁
BufferedImage bi = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics g2 = bi.createGraphics();
g2.setColor(Color.BLACK);
//绘制背景
g2.drawImage(image, 0, 20, this);
g2.setFont(new Font("黑体", Font.BOLD, 20));
g2.drawString("游戏信息:"+message, 130, 60);
//输出时间信息
g2.setFont(new Font("宋体", 0, 14));
g2.drawString("黑方时间:" + blackMessage, 30, 470);
g2.drawString("白方时间:" + whiteMessage, 260, 470); //绘制棋盘
/**
* X=10 Y=70
* X=370 Y=430
* X=370 Y=70
* X=10 Y=430
*/
for (int i = 0; i < 19; i++) {
g2.drawLine(10, 70 + 20 * i, 370, 70 + 20 * i);
g2.drawLine(10 + 20 * i, 70, 10 + 20 * i, 430);
}
//标注点位
g2.fillOval(68, 128, 4, 4);
g2.fillOval(308, 128, 4, 4);
g2.fillOval(308, 368, 4, 4);
g2.fillOval(68, 368, 4, 4); g2.fillOval(68, 248, 4, 4);
g2.fillOval(308, 248, 4, 4);
g2.fillOval(188, 128, 4, 4);
g2.fillOval(188, 368, 4, 4); g2.fillOval(188, 248, 4, 4); //绘制棋子
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
//黑子
if (allChess[i][j] == 1) {
int tempX = i * 20 + 10;
int tempY = j * 20 + 70;
g2.fillOval(tempX - 7, tempY - 7, 14, 14);
}
//白子
if (allChess[i][j] == 2) {
int tempX = i * 20 + 10;
int tempY = j * 20 + 70;
g2.setColor(Color.WHITE);
g2.fillOval(tempX - 7, tempY - 7, 14, 14);
g2.setColor(Color.BLACK);
g2.drawOval(tempX - 7, tempY - 7, 14, 14);
}
}
} g.drawImage(bi,0,0,this);
} //鼠标按键在组件上按下时调用。
@Override
public void mousePressed(MouseEvent e) {
System.out.println("X=" + e.getX() + " Y=" + e.getY());
if (canPlay) {
x = e.getX();
y = e.getY();
//判断点击是否在棋盘内
if (x >= 10 && x <= 370 && y >= 70 && y <= 430) {
x = (x - 10) / 20;
y = (y - 70) / 20; if (allChess[x][y] == 0) {
if (isBlack) {
allChess[x][y] = 1;
isBlack = false;
message="轮到白方";
} else {
allChess[x][y] = 2;
isBlack = true;
message="轮到黑方";
} //判断游戏是否结束
boolean isWin = this.checkWin();
if (isWin) {
JOptionPane.showMessageDialog(this, "游戏结束,"
+ (allChess[x][y] == 1 ? "黑方" : "白方") + "获胜!");
canPlay = false;
}
} this.repaint();
}
} // 点击 【开始游戏】 按钮
if(e.getX() >=400 && e.getX()<=470 && e.getY()>=70 && e.getY()<=100){
int result = JOptionPane.showConfirmDialog(this,"是否重新开始游戏?","",0);
if(result==0){
//1.清空棋盘
allChess = new int[19][19];
//另一种方式:
/*for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
allChess[i][j] = 0;
}
}*/
//2.重置游戏信息
message = "黑方先行";
//3.将下一步下棋的人改为黑方
isBlack = true;
//4.可以游戏标志改为true
canPlay = true;
//5.重置黑白双方时间限制
blackTime = maxTime;
whiteTime = maxTime;
if (maxTime > 0) {
blackMessage = maxTime / 3600 + ":"
+ (maxTime / 60 - maxTime / 3600 * 60) + ":"
+ (maxTime - maxTime / 60 * 60);
whiteMessage = maxTime / 3600 + ":"
+ (maxTime / 60 - maxTime / 3600 * 60) + ":"
+ (maxTime - maxTime / 60 * 60);
t.resume();
} else {
blackMessage = "无限制";
whiteMessage = "无限制";
}
//6.重新绘制窗体
this.repaint();
}
}
//点击 【游戏设置】 按钮
if (e.getX() >= 400 && e.getX() <= 470 && e.getY() >= 120
&& e.getY() <= 150) {
String input = JOptionPane
.showInputDialog("请输入游戏的最大时间(单位:分钟),如果输入0,表示没有时间限制:");
try {
maxTime = Integer.parseInt(input) * 60;
if (maxTime < 0) {
JOptionPane.showMessageDialog(this, "请输入正确信息,不允许输入负数!");
}
if (maxTime == 0) {
int result = JOptionPane.showConfirmDialog(this,
"设置完成,是否重新开始游戏?");
if (result == 0) {
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
allChess[i][j] = 0;
}
}
// 另一种方式 allChess = new int[19][19];
message = "黑方先行";
isBlack = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = "无限制";
whiteMessage = "无限制";
this.canPlay = true;
this.repaint();
}
}
if (maxTime > 0) {
int result = JOptionPane.showConfirmDialog(this,
"设置完成,是否重新开始游戏?");
if (result == 0) {
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
allChess[i][j] = 0;
}
}
// 另一种方式 allChess = new int[19][19];
message = "黑方先行";
isBlack = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = maxTime / 3600 + ":"
+ (maxTime / 60 - maxTime / 3600 * 60) + ":"
+ (maxTime - maxTime / 60 * 60);
whiteMessage = maxTime / 3600 + ":"
+ (maxTime / 60 - maxTime / 3600 * 60) + ":"
+ (maxTime - maxTime / 60 * 60);
t.resume();
this.canPlay = true;
this.repaint();
}
}
} catch (NumberFormatException e1) {
JOptionPane.showMessageDialog(this, "请正确输入信息!");
}
}
//点击 【游戏说明】 按钮
if(e.getX() >=400 && e.getX()<=470 && e.getY()>=170 && e.getY()<=200){
JOptionPane.showMessageDialog(this,"这是一个五子棋游戏程序,黑白双方轮流下棋,当某一方连到五子时游戏结束。");
}
//点击 【认输】 按钮
if(e.getX() >=400 && e.getX()<=470 && e.getY()>=270 && e.getY()<=300){
int result = JOptionPane.showConfirmDialog(this,"是否确认认输?","",0);
if(result==0){
if(isBlack){
JOptionPane.showMessageDialog(this,"黑方已经认输,游戏结束!");
}else{
JOptionPane.showMessageDialog(this,"白方已经认输,游戏结束!");
}
//停止游戏
canPlay = false;
}
}
//点击 【关于】 按钮
if(e.getX() >=400 && e.getX()<=470 && e.getY()>=320 && e.getY()<=350){
JOptionPane.showMessageDialog(this,"本游戏由老徐制作,有问题请联系老徐。");
}
//点击 【退出】 按钮
if(e.getX() >=400 && e.getX()<=470 && e.getY()>=370 && e.getY()<=400){
JOptionPane.showMessageDialog(this,"游戏结束!");
System.exit(0);
}
} private boolean checkWin() {
boolean flag = false;
//统计相连棋子数
//横向
int count = 1;
int color = allChess[x][y]; /*int i = 1;
while (color == allChess[x + i][y]) {
count++;
i++;
} i = 1;
while (color == allChess[x - i][y]) {
count++;
i++;
} if (count >= 5) {
flag = true;
} //竖向
int count2 = 1;
int i2 = 1;
while (color == allChess[x][y+i2]) {
count2++;
i2++;
} i2 = 1;
while (color == allChess[x][y-i2]) {
count2++;
i2++;
} if (count2 >= 5) {
flag = true;
}
// 右上+左下
int count3 = 1;
int i3 = 1;
while (color == allChess[x+i3][y-i3]) {
count3++;
i3++;
} i3 = 1;
while (color == allChess[x-i3][y+i3]) {
count3++;
i3++;
} if (count3 >= 5) {
flag = true;
}
// 左上+右下
int count4 = 1;
int i4 = 1;
while (color == allChess[x-i4][y-i4]) {
count4++;
i4++;
} i4 = 1;
while (color == allChess[x+i4][y+i4]) {
count4++;
i4++;
} if (count4 >= 5) {
flag = true;
}
*/ //判断横向
count = this.checkCount(1,0,color);
if(count>=5){
flag = true;
}else {
//判断纵向
count = this.checkCount(0,1,color);
if(count>=5){
flag = true;
}else {
//判断右上、左下
count = this.checkCount(1, -1, color);
if (count >= 5) {
flag = true;
} else {
//判断右下、左上
count = this.checkCount(1, 1, color);
if (count >= 5) {
flag = true;
}
}
}
}
return flag; } private int checkCount(int xChange, int yChange, int color){
int count = 1;
int tempX = xChange;
int tempY = yChange; while ((x+xChange>=0 && x+xChange <= 18 && y+yChange>=0 && y+yChange <= 18 )&&color == allChess[x+xChange][y+yChange]){
count++;
if(xChange != 0){
xChange++;
}
if(yChange!=0){
if(yChange>0){
yChange++;
}else {
yChange--;
}
}
} xChange = tempX;
yChange = tempY; while ((x-xChange>=0 && x-xChange <= 18 && y-yChange>=0 && y-yChange <= 18 )&&color == allChess[x-xChange][y-yChange]){
count++;
if(xChange != 0){
xChange++;
}
if(yChange!=0){
if(yChange>0){
yChange++;
}else {
yChange--;
}
}
}
return count;
} @Override
public void run() {
// 判断是否有时间限制
if (maxTime > 0) {
while (true) {
if (isBlack) {
blackTime--;
if (blackTime == 0) {
JOptionPane.showMessageDialog(this, "黑方超时,游戏结束!");
}
} else {
whiteTime--;
if (whiteTime == 0) {
JOptionPane.showMessageDialog(this, "白方超时,游戏结束!");
}
}
blackMessage = blackTime / 3600 + ":"
+ (blackTime / 60 - blackTime / 3600 * 60) + ":"
+ (blackTime - blackTime / 60 * 60);
whiteMessage = whiteTime / 3600 + ":"
+ (whiteTime / 60 - whiteTime / 3600 * 60) + ":"
+ (whiteTime - whiteTime / 60 * 60);
this.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(blackTime + " -- " + whiteTime);
}
}
} // 鼠标单击事件
@Override
public void mouseClicked(MouseEvent e) {
} @Override
public void mouseReleased(MouseEvent e) { } @Override
public void mouseEntered(MouseEvent e) { } @Override
public void mouseExited(MouseEvent e) { }
}

Java Swing实现五子棋程序的更多相关文章

  1. java swing 双人五子棋源代码

    import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Toolkit; impo ...

  2. Java Swing 第01记 Hello Word

    首先来一个Java Swing的HelloWord程序. package cn.java.swing.chapter03; import javax.swing.JButton; import jav ...

  3. Java Swing快速构建窗体应用程序

    以前接触java感觉其在桌面开发上,总是不太方便,没有一个好的拖拽界面布局工具,可以快速构建窗体. 最近学习了一下NetBeans IDE 8.1,感觉其窗体设计工具还是很不错的 , 就尝试一下做了一 ...

  4. 解决 GTK+/GNOME 3 环境下 Java Swing 程序使用本地 GTK+ 主题时菜单无边框 bug 的方法

    在 GTK+/GNOME 3 环境下采用默认的 Adwaita 主题时,Java Swing 程序如果使用本地 GTK+ 主题会出现菜单无边框的 bug,这个问题也可能在其他常用的 GTK+ 主题中出 ...

  5. Java swing项目-图书管理系统(swing+mysql+jdbc) 总结

    (一)java Swing的学习. (1)学习如何安装windowbuilder插件的安装. <1>在eclipse中点击help <2>在help的下拉选中选择install ...

  6. Java Swing的进化

    摘 要:Swing已是一个比较老的工具集了,在美观的用户界面出来之前需要开发很长时间.它缺少一些你在开发富UI时所需的组件.幸运地是,像 Substance,SwingX及Java Look-and_ ...

  7. Java Swing事件处理机制

    Java Swing的事件处理机制 Swing GUI启动后,Java虚拟机就启动三个线程,分别为主线程,事件派发线程(也是事件处理线程)和系统工具包线程. 主线程 :负责创建并显示该程序的初始界面: ...

  8. Java Swing界面编程(1)

    写多了jsp,对于页面式的系统已经写烦了,本人也開始着手于java swing的学习,作为菜鸟,仅想用博客记录下我的swing学习的历程.话不多说,首先開始我的第一个窗体化程序. 下面给出源码: pa ...

  9. GUI编程笔记(java)02:java.awt和java.swing包的区别

    1. java.awt和java.swing两者的概述 java.awt:(java的标准包)             Abstract Window ToolKit (抽象窗口工具包),需要调用本地 ...

  10. Java Swing 使用总结(转载)

    随笔转载自:此去经年ぢ 地址:http://www.cnblogs.com/FLFL/p/5369756.html 1.     GUI编程引言 以前的学习当中,我们都使用的是命令交互方式: 例如:在 ...

随机推荐

  1. [转帖]clickHouse单机模式安装部署(RPM安装)

    关于版本和系统的选择 操作系统:Centos-7 ClickHouse: rpm 在安装,20.x 安装前的准备 CentOS7 打开文件数限 在 /etc/security/limits.conf ...

  2. [转帖]HTTP状态码、请求方法、响应头信息

    https://www.cnblogs.com/pachongshangdexuebi/p/5279608.html HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求. ...

  3. [转帖]2.20 Native Operating System Tools

    https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr020.html#BABBHHIE 2.20  ...

  4. SQLSERVER 数据库根据LCK_M_S对应的waitsorce 查看被锁的表信息的简单方法

    公司一个开发大牛召冠总搞过一个 DMSQLMONITOR 工具 能够识别Oracle以及SQLSERVER 数据库的锁和事务等问题, 非常好用 今天环境出现了不可用的情况, 所以这边着急进行一下问题分 ...

  5. 【JS 逆向百例】网洛者反爬练习平台第一题:JS 混淆加密,反 Hook 操作

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  6. 解决Chrome翻译无法使用

    截止2022年11月3日自己ping出的ip不可用了 可以用以下ip 172.217.215.90 172.253.115.90 142.250.126.90 142.250.10.90 142.25 ...

  7. Leetcode 2题 两数相加

    题目链接 https://leetcode-cn.com/problems/add-two-numbers/ 题目描述 给你两个非空的链表,表示两个非负的整数.它们每位数字都是按照逆序的方式存储的,并 ...

  8. 强大的AWS lambda

    AWS强大的lambda 自从几年前换工作后,我所参与的项目一直都是基于AWS云服务的架构,我慢慢对serverless的相关基础建设有了一定了解和实践经验.其中lambda是我心中最强大的serve ...

  9. 策略模式学习,使用go实现策略模式

    策略模式 定义 优点 缺点 使用场景 代码实现 策略模式和工厂模式的区别 参考 策略模式 定义 策略模式定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到客户端的使用 ...

  10. GPTs prompts灵感库:创意无限,专业级创作指南,打造吸睛之作的秘诀

    GPTs prompts灵感库:创意无限,专业级创作指南,打造吸睛之作的秘诀 优质prompt展示 1.1 极简翻译 中英文转换 你是一个极简翻译工具,请在对话中遵循以下规则: - Prohibit ...