这几天做了一个小应用,单机版的五子棋开发。分享一下源代码。
总共有三个类文件,分别为:StartChessJFrame.java, Point.java, ChessBoard.java
//StartChessJFrame.java
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
/**
* This is main window.
* @author Logan
* 主函数文件,包括顶部菜单和底部菜单,包括主面板。
*/
public class StartChessJFrame extends JFrame{
//对战面板
private ChessBoard chessBoard;
//工具条面板
private JPanel toolbar;
//“重新开始”按钮,“悔棋”按钮,“退出”按钮
private JButton startButton;
private JButton backButton;
private JButton exitButton;
//菜单栏
private JMenuBar menuBar;
//系统菜单
private JMenu sysMenu;
//“重新开始”,“退出”和“悔棋”菜单项
private JMenuItem startMenuItem;
private JMenuItem exitMenuItem;
private JMenuItem backMenuItem;
public StartChessJFrame(){
//设置标题
setTitle("单机版五子棋");
//初始化面板对象
//创建和添加菜单
chessBoard = new ChessBoard();
//初始化菜单栏
menuBar = new JMenuBar();
//初始化菜单
sysMenu = new JMenu("系统");
//初始化菜单项
startMenuItem = new JMenuItem("重新开始");
exitMenuItem = new JMenuItem("退出");
backMenuItem = new JMenuItem("悔棋");
//将三个菜单项添加到菜单上
sysMenu.add(startMenuItem);
sysMenu.add(exitMenuItem);
sysMenu.add(backMenuItem);
//初始化按钮事件监听器内部类
MyItemListener lis = new MyItemListener();
//将三个菜单项注册到事件监听器上
this.startMenuItem.addActionListener(lis);
//不知道为什么这两个没有this
backMenuItem.addActionListener(lis);
exitMenuItem.addActionListener(lis);
//将“系统”菜单添加到菜单栏上
menuBar.add(sysMenu);
//将menuBar设置为菜单栏
setJMenuBar(menuBar);
//工具面板栏实例化
toolbar = new JPanel();
//三个按钮初始化
startButton = new JButton("重新开始");
backButton = new JButton("悔棋");
exitButton = new JButton("退出");
//将工具面板按钮用FlowLayout布局
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
//将三个按钮添加到工具面板上
toolbar.add(startButton);
toolbar.add(backButton);
toolbar.add(exitButton);
//将三个按钮注册监听事件
startButton.addActionListener(lis);
backButton.addActionListener(lis);
exitButton.addActionListener(lis);
//将工具面板布局到界面“南”方也就是下面
add(toolbar,BorderLayout.SOUTH);
//将面板对象添加到窗体上
add(chessBoard);
//设置界面关闭事件
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//自适应大小
pack();
}
//事件监听器内部类
private class MyItemListener implements ActionListener{
public void actionPerformed(ActionEvent e){
//取得事件源
Object obj = e.getSource();
//重新开始
//JFiveFrame.this内部类引用外部类
if(obj == StartChessJFrame.this.startMenuItem||obj == startButton){
System.out.println("重新开始...");
chessBoard.restartGame();
}
else if(obj == exitMenuItem || obj == exitButton){
//结束应用程序
System.exit(0);
}
else if(obj == backMenuItem || obj == backButton){
//悔棋
System.out.println("悔棋...");
chessBoard.goback();
}
}
}
public static void main(String [] args){
//创建主框架
StartChessJFrame f = new StartChessJFrame();
//显示主框架
f.setVisible(true);
}
}
//Point.java
//点类,
import java.awt.Color;
public class Point {
//棋盘中的x索引
private int x;
//期盼中的y索引
private int y;
//颜色
private Color color;
//直径
public static final int DIAMETER = 30;
public Point(int x, int y, Color color){
this.x = x;
this.y = y;
this.color = color;
}
//拿到棋盘中的x索引
public int getX(){
return x;
}
//拿到棋盘中的y索引
public int getY(){
return y;
}
//拿到颜色
public Color getColor(){
return color;
}
}
//ChessBoard.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
/**
* 五子棋-棋盘类
* @author Logan
* 棋盘主函数。
*/
public class ChessBoard extends JPanel implements MouseListener{
//边距
public static final int MARGIN = 30;
//网格间距
public static final int GRID_SPAN = 30;
//棋盘行数
public static final int ROWS = 10;
//棋盘列数
public static final int COLS = 10;
//初始每个数组元素为null
Point[] chessList = new Point[(ROWS+1)*(COLS+1)];
//默认开始是黑旗先下
boolean isBlack = true;
//游戏是否结束
boolean gameover = false;
//当前棋盘的旗子个数
int chessCount;
//当前刚下的旗子的索引
int xIndex, yIndex;
//绘制
public ChessBoard(){
//设置背景颜色为橘黄色
setBackground(Color.ORANGE);
//添加监听器
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));
}
});
}
public void paintComponent(Graphics g){
//画棋盘
super.paintComponent(g);
//画横线
for(int i = 0;i<=ROWS;i++){
g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);
}
//画竖线
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的坐标
int xPos = chessList[i].getX()*GRID_SPAN+MARGIN;
//网格交叉点y的坐标
int yPos = chessList[i].getY()*GRID_SPAN+MARGIN;
//设置颜色
g.setColor(chessList[i].getColor());
//***这个函数不知道干什么的***
g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);
//标记最后一个旗子的红色矩形框
//最后一个旗子
if(i == chessCount - 1){
g.setColor(Color.red);
g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER);
}
}
}
//鼠标在组件上按下时调用
public void mousePressed(MouseEvent e){
//游戏已经结束,不能下
if(gameover)
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)
return;
//x,y位置已经有旗子存在,不能下
if(findChess(xIndex,yIndex))
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){
}
//鼠标进入到组件上时调用
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 <= ROWS;x++){
Color c = isBlack?Color.black:Color.white;
if(getChess(x,yIndex,c)!=null){
continueCount++;
}
else{
break;
}
}
//判断记录数大于等于5,即表示此方获胜
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;y<=ROWS&&x>=0;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;y>=0&&x>=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;y<=ROWS&&x<=COLS;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;
}
//定义getChess
private Point getChess(int xIndex,int yIndex,Color color){
for(Point c:chessList){
if(c != null && c.getX() == xIndex && c.getY() == yIndex && c.getColor() == color){
return c;
}
}
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();
}
//矩形
public Dimension getPreferredSize(){
return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2+GRID_SPAN*ROWS);
}
}
总结:这是一个比较简单的小设计,但是很值得初学者,代码量不多,大概只有500行左右的代码,而且能加深对面向对象编程的了解。