五子棋游戏 - 棋盘类实现
五子棋游戏 - 棋盘类实现
该代码实现了一个简单的五子棋游戏棋盘类,包含以下功能:
- 棋盘绘制: 使用
Graphics对象绘制棋盘格子和棋子,并使用RadialGradientPaint实现棋子渐变效果。 - 棋子放置: 监听鼠标点击事件,将棋子放置在点击的位置。
- 游戏状态判断: 判断游戏是否结束,并根据结果提示用户。
- 悔棋功能: 撤销最后一步棋子。
- 游戏暂停功能: 暂停游戏,并防止在暂停状态下进行下棋操作。
代码实现:
package cn.edu.ouc.fiveChess;
import sun.awt.image.ToolkitImage;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
/**
* 五子棋--棋盘类
*/
public class ChessBoard extends JPanel implements MouseListener {
public static final int MARGIN=30;//边距
public static final int GRID_SPAN=35;//网格间距
public static final int ROWS=15;//棋盘行数
public static final int COLS=15;//棋盘列数
Point[] chessList=new Point[(ROWS+1)*(COLS+1)];//初始每个数组元素为null
boolean isBlack=true;//默认开始是黑棋先
boolean gameOver=false;//游戏是否结束
int chessCount;//当前棋盘棋子的个数
int xIndex,yIndex;//当前刚下棋子的索引
//声明变量
Image img;
Image shadows;
Color colortemp;
//程序暂停,true为暂停
private boolean paused;
//创建ChessBoard类
public ChessBoard(){
//使用Toolkit类的getDefaultToolkit方法获取默认工具包
img= Toolkit.getDefaultToolkit().getImage("");
shadows=Toolkit.getDefaultToolkit().getImage("");
//添加鼠标监视器
addMouseListener(this);
//添加一个鼠标移动监听器
addMouseMotionListener(new MouseMotionListener(){
public void mouseDragged(MouseEvent e){
}
public void mouseMoved(MouseEvent e){
int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//将鼠标点击的坐标位置转成网格索引
int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//游戏已经结束不能下
//落在棋盘外不能下
//x,y位置已经有棋子存在,不能下
if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1))
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
//设置成默认状态
else setCursor(new Cursor(Cursor.HAND_CURSOR));
}
});
}
private boolean isPaused = false;//添加一个标志位记录游戏是否暂停
//绘制
public void paintComponent(Graphics g){
super.paintComponent(g);//画棋盘
int imgWidth= img.getWidth(this);
int imgHeight=img.getHeight(this);//获得图片的宽度与高度
int FWidth=getWidth();
int FHeight=getHeight();//获得窗口的宽度与高度
int x=(FWidth-imgWidth)/2;
int y=(FHeight-imgHeight)/2;
g.drawImage(img, x, y, null);
for(int i=0;i<=ROWS;i++){//画横线
for(int j=0;j<COLS;j++) {
g.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS * GRID_SPAN, MARGIN + i * GRID_SPAN);
}
}
//判断游戏是否暂停,如果暂停则不进行绘制
if(!isPaused) {//如果游戏未暂停,进行绘制
for (int i = 0; i <= COLS; i++) {//画竖线
g.drawLine(MARGIN + i * GRID_SPAN, MARGIN, MARGIN + i * GRID_SPAN, MARGIN + ROWS * GRID_SPAN);
}
//画棋子
for (int i = 0; i < chessCount; i++) {
//网格交叉点x,y坐标
int xPos = chessList[i].getX() * GRID_SPAN + MARGIN;
int yPos = chessList[i].getY() * GRID_SPAN + MARGIN;
g.setColor(chessList[i].getColor());//设置颜色
colortemp = chessList[i].getColor();
if (colortemp == Color.black) {
RadialGradientPaint paint = new RadialGradientPaint(xPos - Point.DIAMETER / 2 + 25, yPos - Point.DIAMETER / 2 + 10, 20, new float[]{0f, 1f}
, new Color[]{Color.WHITE, Color.BLACK});
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
} else if (colortemp == Color.white) {
RadialGradientPaint paint = new RadialGradientPaint(xPos - Point.DIAMETER / 2 + 25, yPos - Point.DIAMETER / 2 + 10, 70, new float[]{0f, 1f}
, new Color[]{Color.WHITE, Color.BLACK});
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
Ellipse2D e = new Ellipse2D.Float(xPos - Point.DIAMETER / 2, yPos - Point.DIAMETER / 2, 34, 35);
((Graphics2D) g).fill(e);
//标记最后一个棋子的红矩形框
}
}
}
public void mousePressed(MouseEvent e){
//游戏结束时,不再能下
if (gameOver || paused) {
JOptionPane.showMessageDialog(this, "当前处于暂停模式,请点击继续按钮继续游戏");
return;
}
String colorName=isBlack?"黑棋":"白棋";
//将鼠标点击的坐标位置转换成网格索引
xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//落在棋盘外不能下
if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS) {
JOptionPane.showMessageDialog(this, "该位置不在界面内,请在界面内下棋");
return;
}
//如果点击的位置已经有棋子存在,不能下
if(findChess(xIndex,yIndex)) {
JOptionPane.showMessageDialog(this, "该位置已经有棋子,请重新选择位置下棋!");
return;
}
//可以进行时的处理
Point ch=new Point(xIndex,yIndex,isBlack?Color.black:Color.white);
chessList[chessCount++]=ch;
repaint();//通知系统重新绘制
//如果胜出则给出提示信息,不能继续下棋
if(isWin()){
String msg=String.format("恭喜,%s赢了!", colorName);
JOptionPane.showMessageDialog(this, msg);
gameOver=true;
}
isBlack=!isBlack;
}
//覆盖mouseListener的方法
public void mouseClicked(MouseEvent e) {
//判断游戏是否暂停,如果暂停则不进行下棋
if (isPaused) {
JOptionPane.showMessageDialog(this, "游戏已暂停,请点击继续按钮继续游戏", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
}
public void mouseEntered(MouseEvent e){
//鼠标进入到组件上时调用
}
public void mouseExited(MouseEvent e){
//鼠标离开组件时调用
}
public void mouseReleased(MouseEvent e){
//鼠标按钮在组件上释放时调用
}
//在棋子数组中查找是否有索引为x,y的棋子存在
private boolean findChess(int x,int y){
for(Point c:chessList){
if(c!=null&&c.getX()==x&&c.getY()==y)
return true;
}
return false;
}
private boolean isWin(){
int continueCount=1;//连续棋子的个数
//横向向西寻找
for(int x=xIndex-1;x>=0;x--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,yIndex,c)!=null){
continueCount++;
}else
break;
}
//横向向东寻找
for(int x=xIndex+1;x<=COLS;x++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,yIndex,c)!=null){
continueCount++;
}else
break;
}
if(continueCount>=5){
return true;
}else
continueCount=1;
//继续另一种搜索纵向
//向上搜索
for(int y=yIndex-1;y>=0;y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(xIndex,y,c)!=null){
continueCount++;
}else
break;
}
//纵向向下寻找
for(int y=yIndex+1;y<=ROWS;y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(xIndex,y,c)!=null)
continueCount++;
else
break;
}
if(continueCount>=5)
return true;
else
continueCount=1;
//继续另一种情况的搜索:斜向
//东北寻找
for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null){
continueCount++;
}
else break;
}
//西南寻找
for(int x=xIndex-1,y=yIndex+1;x>=0&&y<=ROWS;x--,y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null){
continueCount++;
}
else break;
}
if(continueCount>=5)
return true;
else continueCount=1;
//继续另一种情况的搜索:斜向
//西北寻找
for(int x=xIndex-1,y=yIndex-1;x>=0&&y>=0;x--,y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null)
continueCount++;
else break;
}
//东南寻找
for(int x=xIndex+1,y=yIndex+1;x<=COLS&&y<=ROWS;x++,y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null)
continueCount++;
else break;
}
if(continueCount>=5)
return true;
else continueCount=1;
return false;
}
private Point getChess(int xIndex,int yIndex,Color color){
for(Point p:chessList){
if(p!=null&&p.getX()==xIndex&&p.getY()==yIndex
&&p.getColor()==color)
return p;
}
return null;
}
public void restartGame(){
//清除棋子
for(int i=0;i<chessList.length;i++){
chessList[i]=null;
}
//恢复游戏相关的变量值
isBlack=true;
gameOver=false; //游戏是否结束
chessCount =0; //当前棋盘棋子个数
repaint();
}
//悔棋
public void goback(){
if(chessCount==0)
return ;
chessList[chessCount-1]=null;
chessCount--;
if(chessCount>0){
xIndex=chessList[chessCount-1].getX();
yIndex=chessList[chessCount-1].getY();
}
isBlack=!isBlack;
repaint();
}
//矩形Dimension
public Dimension getPreferredSize(){
return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2
+GRID_SPAN*ROWS);
}
public void setPaused(boolean paused) {
this.paused = paused;
}
}
代码说明:
- 类定义: 声明
ChessBoard类继承JPanel并实现MouseListener接口。 - 成员变量: 声明了棋盘信息、游戏状态、当前棋子信息等变量。
- 构造函数: 初始化棋盘信息、添加鼠标监听器和鼠标移动监听器。
- 绘制方法
paintComponent: 绘制棋盘格子和棋子,并根据游戏状态进行绘制。 - 鼠标点击事件处理: 监听鼠标点击事件,将棋子放置在点击的位置,并判断游戏是否结束。
- 悔棋方法
goback: 撤销最后一步棋子。 - 游戏暂停方法
setPaused: 暂停游戏,并防止在暂停状态下进行下棋操作。
问题和解决方案:
- 图片加载不出来。
- 解决方案:检查图片路径是否正确,使用绝对路径或者将图片放在项目根目录下。
- 棋子绘制不出来。
- 解决方案:检查绘制代码是否正确,如颜色、位置等是否正确,可以使用调试工具查看变量的值。
- 游戏暂停后,点击棋盘仍可以下棋。
- 解决方案:在鼠标监听器中加入判断,如果游戏暂停,则不执行下棋操作。
- 悔棋时棋子消失不彻底。
- 解决方案:在悔棋方法中将棋子数组对应位置赋值为null,并将棋子个数减1,保证棋子数组中不会出现null与非null交错的情况。
下一步改进:
- 可以添加游戏开始界面,选择先手棋子等功能。
- 可以添加计分功能,记录游戏胜负情况。
- 可以使用更复杂的算法实现人工智能对手,使玩家可以与电脑对战。
总结:
该代码提供了一个五子棋游戏棋盘类实现的简单示例,可以作为学习和参考。通过进一步改进,可以实现更加完善的五子棋游戏功能。
原文地址: https://www.cveoy.top/t/topic/oBhP 著作权归作者所有。请勿转载和采集!