JAVA小游戏之五子棋(免费下载源码)

本文描述了一个开发者使用JavaSwing框架开发的19x19围棋游戏,包括棋盘布局、按钮控制、落子区域、输赢判断及简单效果展示,展示了从零开始开发的基本过程和关键技术应用。
摘要由CSDN通过智能技术生成

1. 概述        

有一天突然挺无聊的, 就想着去熟悉下JAVA的界面程序开发. 平常虽然都是做WEB开发, 但想来思路都是差不多的. 于是就查看了下Swing的介绍以及一些基本的组件.  但由于工作原因, 想起的时候就写一点, 想起的时候就写一点, 直到今天才做完. 其实整个游戏是很简单的, 如果从头开始做(指的是无Swing基础), 我觉得差不多要用3天时间去完成, 主要耗时间的点在对组建的尝试, 毕竟和WEB的布局还是有差异的. 源代码大家可以去我的资源里面下载.

2. 开发环境

操作系统:  Ubuntu 18.04

JDK: openjdk version "17.0.7" 2023-04-18

Eclipse: Version: 2018-12 (4.10.0) (比较古老了, 但一直懒的换)

Maven:  3.3.9  (一样古老的版本, 大家自己可以用最新的版本)

3. 效果展示

3.1 棋盘布局

3.1.1 重新开始按钮

点击该按钮会清空棋盘上的棋子, 并把参数初始化到默认值.

// 按钮添加点击事件
		gameStartBtn.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {
				GameUI.clearPieces();
			}
		});

...

// 遍历棋盘上的棋子进行清除
public static void clearPieces() {
		ChessPieceDropArea.chessPieceColor = 0;
		for(int i = 0; i < 19; i++) {
			for(int j = 0; j < 19; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = chessPieceDropArea[i][j];
				chessPieceDropAreaObj.isDroped = false;
				chessPieceDropAreaObj.isWhite = false;
				chessPieceDropAreaObj.repaint();
				showInfoOfDropBlackPiece();
			}
		}
	}

3.1.2 信息Label

显示该下什么颜色的棋子, 默认黑棋先下. 每次落子后会修改该信息.

3.1.3 下棋区域

19*19的围棋棋盘, 并在对应的位置画上了星(黑色点点). 这里主要用到JPanel的paintComponent方法, 重写该方法, 在对应的位置画圆.

@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		
		int width = this.getWidth();
		int height = this.getHeight();
		
		for(int i = 1; i <= 19; i++) {
			g.drawLine(chessPieceDiameter, chessPieceDiameter * i, width - chessPieceDiameter, chessPieceDiameter * i);
		}
		
		for(int i = 1; i <= 19; i++) {
			g.drawLine(chessPieceDiameter * i, chessPieceDiameter, chessPieceDiameter * i, height - chessPieceDiameter);
		}
		// 
		int startRadio = 5;
		int startWidth = 2 * startRadio;
		// 左上角星
		g.fillOval(chessPieceDiameter * 4 - startRadio, chessPieceDiameter * 4 - startRadio, startWidth, startWidth);
		// 上中星
		g.fillOval(chessPieceDiameter * 10 - startRadio, chessPieceDiameter * 4 - startRadio, startWidth, startWidth);
		// 右上角星
		g.fillOval(chessPieceDiameter * 16 - startRadio, chessPieceDiameter * 4 - startRadio, startWidth, startWidth);
		// 中左星
		g.fillOval(chessPieceDiameter * 4 - startRadio, chessPieceDiameter * 10 - startRadio, startWidth, startWidth);
		// 在天元处画一个点
		g.fillOval(chessPieceDiameter * 10 - startRadio, chessPieceDiameter * 10 - startRadio, startWidth, startWidth);
		// 中右星
		g.fillOval(chessPieceDiameter * 16 - startRadio, chessPieceDiameter * 10 - startRadio, startWidth, startWidth);
		// 下左星
		g.fillOval(chessPieceDiameter * 4 - startRadio, chessPieceDiameter * 16 - startRadio, startWidth, startWidth);
		// 下中星
		g.fillOval(chessPieceDiameter * 10 - startRadio, chessPieceDiameter * 16 - startRadio, startWidth, startWidth);
		// 下右星
		g.fillOval(chessPieceDiameter * 16 - startRadio, chessPieceDiameter * 16 - startRadio, startWidth, startWidth);
	}

3.2 下棋

3.2.1 落子区

在棋盘之上添加了19*19个落子的JPanel区域, 每个区域默认设定是透明的.  当鼠标点击该区域后, 应用会根据当前落子的颜色绘制相应的棋子. 这里默认设置的棋子的直径为40.

		// 画落子区
		chessPieceDropArea = new ChessPieceDropArea[19][19];
		for(int i = 0; i < 19; i++) {
			for(int j = 0; j < 19; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = new ChessPieceDropArea(i, j, CHESS_PIECE_DIAMETER);
				chessPieceDropArea[i][j] = chessPieceDropAreaObj;
				chessPieceDropAreaObj.setBounds(CHESS_PIECE_DIAMETER/2+i*CHESS_PIECE_DIAMETER
						, CHESS_PIECE_DIAMETER/2+j*CHESS_PIECE_DIAMETER
						, CHESS_PIECE_DIAMETER
						, CHESS_PIECE_DIAMETER);
				chessPieceDropAreaObj.setOpaque(false);
//				chessPieceDropAreaObj.setBorder(new LineBorder(Color.black, 1));
				chessBoard.add(chessPieceDropAreaObj);
			}

3.2.2 棋子

当时的设计是, 落子区触发点击事件后进行重绘, 重绘会触发paintComponent, 然后我们就可以去根据条件进行绘制棋子了.

	@Override
	public void mouseClicked(MouseEvent e) {
		if(isDroped) {
			// 已经有棋子不可以再点击
			return;
		}
		
		isDroped = true;
		if(chessPieceColor == 0) {
			isWhite = false;
			chessPieceColor = 1;
			GameUI.showInfoOfDropWhitePiece();
		}else {
			isWhite = true;
			chessPieceColor = 0;
			GameUI.showInfoOfDropBlackPiece();
		}
		this.repaint();
		
		// 判断结果
		if(GameUI.judge(this.isWhite)) {
			//游戏结束
			if(this.isWhite) {
				JOptionPane.showMessageDialog(null, "白棋赢", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
			}else {
				JOptionPane.showMessageDialog(null, "黑棋赢", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
			}
			GameUI.clearPieces();
		}		
	}

...

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		
		if(!isDroped) {
			return;
		}
		
		// 画一个黑色边框的透明棋子
		g.setColor(Color.black);
		g.drawOval(0, 0, chessPieceDiameter, chessPieceDiameter);
		
		// 根据落子的颜色进行填充
		if (isWhite) {
			g.setColor(Color.white);
			g.fillOval(0, 0, chessPieceDiameter, chessPieceDiameter);
		} else {
			g.setColor(Color.black);
			g.fillOval(0, 0, chessPieceDiameter, chessPieceDiameter);
		}	
	}

3.3 判定输赢

3.3.1 输赢判断

每当落子后, 都会触发输赢判断. 判断逻辑主要是:

1. 遍历每一行, 确认是否有5子相连

2. 遍历每一列, 确认是否有5子相连

3. 遍历每一条斜线, 确认是否有5子相连

4. 遍历每一条反斜线, 确认是否有5子相连

// true表示已经判断出结果, 对奕结束
	public static boolean judge(boolean isWhite) {
		System.out.println("isWhite="+isWhite);
		// 检查横线上是否有五个相同的棋子
		int count = 0;
		for(int i = 0; i < 19; i++) {
			for(int j = 0; j < 19; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = chessPieceDropArea[i][j];
				if(!chessPieceDropAreaObj.isDroped || chessPieceDropAreaObj.isWhite != isWhite) {
					// 没有落子, 或者已经断开, 重新从0计数
					if(count >=5) {
						return true;
					}
					count = 0;					
				}else {
					count++;
					if(count >=5) {
						return true;
					}
				}
			}
			// 新的一行
			count = 0;
		}	
		// 检查每一列是否有五个相同的棋子
		count = 0;
		for(int i = 0; i < 19; i++) {
			for(int j = 0; j < 19; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = chessPieceDropArea[j][i];
				if(!chessPieceDropAreaObj.isDroped || chessPieceDropAreaObj.isWhite != isWhite) {
					// 没有落子, 或者已经断开, 重新从0计数
					if(count >=5) {
						return true;
					}
					count = 0;					
				}else {
					count++;
					if(count >=5) {
						return true;
					}
				}
			}
			// 新的一行
			count = 0;
		}
		// 检查斜线上是否有五个相同的棋子
		count = 0;
		for(int i = 18; i > 0; i--) {
			int tmp = i;
			for(int j = 0; j < 19 && tmp < 19; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = chessPieceDropArea[tmp][j];
				if(!chessPieceDropAreaObj.isDroped || chessPieceDropAreaObj.isWhite != isWhite) {
					// 没有落子, 或者已经断开, 重新从0计数
					if(count >=5) {
						return true;
					}
					count = 0;					
				}else {
					count++;
					if(count >=5) {
						return true;
					}
				}
				tmp++;
			}
		}		
		// 检查反斜线上是否有五个相同的棋子
		count = 0;
		for(int i = 0; i < 19; i++) {
			int tmp = i;
			for(int j = 0; j < 19 && tmp >= 0; j++) {
				ChessPieceDropArea chessPieceDropAreaObj = chessPieceDropArea[tmp][j];
				if(!chessPieceDropAreaObj.isDroped || chessPieceDropAreaObj.isWhite != isWhite) {
					// 没有落子, 或者已经断开, 重新从0计数
					if(count >=5) {
						return true;
					}
					count = 0;					
				}else {
					count++;
					if(count >=5) {
						return true;
					}
				}
				tmp--;
			}
		}	
		return false;
	}

3.3.2 展示结果

一旦确认输赢, 弹出信息框展示结果. 退出信息框后重新初始化棋盘.

// 判断结果
		if(GameUI.judge(this.isWhite)) {
			//游戏结束
			if(this.isWhite) {
				JOptionPane.showMessageDialog(null, "白棋赢", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
			}else {
				JOptionPane.showMessageDialog(null, "黑棋赢", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
			}
			GameUI.clearPieces();
		}	

4. 总结

这只是一个测试项目, 实现了基本功能, 但还有很多优化的项. 尤其设计这块. 如果大家喜欢的话, 一键三连哦.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值