首先感谢08年MLDN出的这个培训视频,我把代码和文档整理了一下,发布出来给需要学习Swing的朋友。
https://gitee.com/indexman/gobang
JFrame:窗体
JOptionPane:对话框
MouseListener:鼠标事件
Graphics:绘制二维图像
Thread:线程类
计算棋盘中每一条线的间距:这里用的是19X19的围棋棋盘,
总宽度为360px, 分成18份,每份是20px
黑子:一个实心的黑圆表示
白子:一个空心的黑圆+一个实心的白圆表示
repaint() 方法表示重新执行一次paint()方法。
通过一个二维数组来保存之前下过的所有棋子。
依据 五子棋 的基本游戏规则,判断是否有同一颜色的棋子连城5个。
完成五子棋游戏的核心算法
这里可以把核心算法总结成一个灵活的方法。
提示信息的保存
使用双缓冲技术
开始游戏:重新开始游戏
游戏设置: 设置倒计时时间
游戏说明:用来说明游戏规则和操作
认输:某一方放弃游戏,投子认负
关于:显示游戏制作者
退出:退出程序
-----------------------------------------------------分割线------------------------------------------------------
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");
}
}
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) {
}
}