设计一个五子棋游戏
游戏采用15×15棋盘,通过二维数组记录棋子位置,支持黑白交替落子,并实现水平/垂直/斜向五连珠判定。特色功能包括:立体棋子渲染、步数统计、胜负提示以及完整的棋局回放系统。
------------------------------------------------------------------------------------------
一、设计游戏面板
先创建自定义面板类public class GameUI {}
显示游戏界面
public void initUI(){}
JFrame jf = new JFrame();
jf.setSize(900,900);
jf.setTitle("五子棋游戏");
居中显示 jf.setLocationRelativeTo(null);
退出进程 jf.setDefaultCloseOperation(3);
用一个独立的面板对象绘制棋盘
因为自定面板类才有绘制棋盘,棋子功能
~写一个MPanel类负责棋盘绘制和棋子显示~
public class MPanel extends JPanel implements Config {}
引用传递
public Chess[] chessArr;
重写paint方法
public void paint(Graphics g){
***1.保留绘制组件的功能
super 表示当前类的父类对象
this 表示本类对象
super.paint(g);
System.out.println("paint....");
***2.绘制棋盘,棋子
硬编码
for(int i=0;i<LINE;i++) {
g.drawLine(X0, Y0+i*SIZE, (LINE-1)*SIZE+X0, Y0+i*SIZE);
g.drawLine(X0+i*SIZE, Y0, X0+i*SIZE, (LINE-1)*SIZE+Y0);
}
重绘所有棋子数据
for(int i=0;i<chessArr.length;i++){
Chess c = chessArr[i];
if(c != null) {
c.drawChess(g);
}
}
}
MPanel chessPanel = new MPanel();
chessPanel.setBackground(Color.GREEN);
jf.add(chessPanel);
JPanel eastPanel = new JPanel();
eastPanel.setPreferredSize(new Dimension(80,0));
eastPanel.setLayout(new FlowLayout(FlowLayout.CENTER,0,30));
jf.add(eastPanel,BorderLayout.EAST);
功能按钮
String[] name = {"开始","悔棋","复盘"};
for(int i=0;i<name.length;i++){
JButton jbu = new JButton(name[i]);
eastPanel.add(jbu);
jbu.addActionListener(listener);
}
标签:显示步数
JLabel label = new JLabel("步数:0");
label.setFont(new Font("宋体",Font.BOLD,18));
eastPanel.add(label);
jf.setVisible(true);
从窗体上获取画笔
Graphics g = chessPanel.getGraphics();
传递画笔对象
listener.gr = g;
listener.chessPanel = chessPanel;
listener.label=label;
把chessArr数组从GameListener中传递给MPanel类
chessPanel.chessArr = listener.chessArr;
应用需要一个主函数
public static void main(String[] args) {
GameUI ui = new GameUI();
ui.initUI();
}
------------------------------------------------------------------------------------------
二、通过Config接口定义棋盘常量来方便修改与应用数值
实现接口:implements 继承类:extends
实现接口一定要重写接口中所有的抽象方法
自定义接口public interface Config {}
常量
public int X0=50,Y0=50,SIZE=50,LINE=15,CHESS=50;
-----------------------------------------------------------------------------------------
三、创建GameListener类来处理鼠标/按钮事件,实现落子、悔棋、复盘功能并为页面添加监听器
创建监听器类public class GameListener extends MouseAdapter implements Config, ActionListener {}
引用传递
保存传递过来的画笔对象 public Graphics gr;
棋子计数器 public int count = 0;
保存当前棋子的交点值 public int chessX, chessY;
保存当前棋子颜色 public Color color;
保存棋子对象
public Chess[] chessArr = new Chess[200];
定义二维数组保存棋子颜色
二维数组:一维-行数 二维-列数 => int[行][列];
public int[][] winArr = new int[LINE][LINE];
控制开始游戏的标记位 public boolean start = false;
绘制棋盘面板对象 public MPanel chessPanel;
public JLabel label;
在自定义面板类中添加监听器
GameListener listener = new GameListener();
给窗体添加鼠标监听器方法
chessPanel.addMouseListener(listener);
~重写监听器处理方法~
1、重写动作监听器处理方法
public void actionPerformed(ActionEvent e){
String name = e.getActionCommand();
switch (name){
case "开始":
start = true;
break;
case "悔棋":
retreat();
break;
case "复盘":
replay();
break;
}
}
***悔棋
public void retreat(){
//取出最后一颗棋子
count--;
Chess c = chessArr[count];
//清空二维数组数据
winArr[c.chessY][c.chessX] = 0;
chessArr[count] = null;
//刷新棋盘:
chessPanel.repaint();
}
***复盘
public void replay(){
按顺序备份所有的棋子数据
Chess[] copyArr = new Chess[count];
for(int i=0;i<count;i++){
copyArr[i] = chessArr[i];
}
先清空棋盘上数据
for(int i=0;i<chessArr.length;i++){
chessArr[i] = null;
}
chessPanel.paint(gr);
按顺序重新把所有棋子再画一遍
for(int i=0;i<copyArr.length;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Chess c = copyArr[i];
c.drawChess(gr);
}
}
2、重写鼠标监听器处理方法
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
System.out.println("点击!");
计算棋子交点值
if ((x - X0) % SIZE > SIZE / 2) {
chessX = (x - X0) / SIZE + 1;
} else {
chessX = (x - X0) / SIZE;
}
if ((y - Y0) % SIZE > SIZE / 2) {
chessY = (y - Y0) / SIZE + 1;
} else {
chessY = (y - Y0) / SIZE;
}
开始游戏
! 非 对象结果取反
if(!start){
return;
}
覆盖问题
if(winArr[chessY][chessX] != 0){
System.out.println("....");
当前方法的返回值类型是void 表示不需要返回数据
return; //结束当前方法的调用
}
取余 %
if (count % 2 == 0) {
color = Color.BLACK;
保存棋子颜色
把棋子的交点值看作是二维数组的下标
winArr[chessY][chessX] = 1;
} else {
color = Color.WHITE;
winArr[chessY][chessX] = 2;
}
~创建Chess 对象,保存其数据,并绘制出来~
Chess类实现棋子绘制与数据存储
根据棋子对象设计对应的类public class Chess implements Config {}
属性
交点值 public int chessX, chessY;
当前棋子颜色 public Color color = Color.BLACK;
方法
构造方法:public 类名(参数类型 参数名,,){ 方法体...}
作用:1.创建对象 2.同时给多个属性初始化
public Chess(int chessX, int chessY, Color color) {
this.chessX = chessX;
this.chessY = chessY;
this.color = color;
}
根据保存数据的还原图形
1.绘制立体棋子(颜色渐变) 2.绘制图片
public void drawChess(Graphics g) {
if (color == Color.BLACK) {
for (int i = 0; i < CHESS; i++) {
g.setColor(new Color(i*2,i*2,i*2));
g.fillOval(chessX * SIZE + X0 - CHESS / 2+i/2, chessY * SIZE + Y0 - CHESS / 2+i/2,
CHESS - i, CHESS - i);
}
} else if (color == Color.WHITE) {
for (int i = 0; i < CHESS; i++) {
g.setColor(new Color((127-i)*2,(127-i)*2,(127-i)*2));
g.fillOval(chessX * SIZE + X0 - CHESS / 2+i/2, chessY * SIZE + Y0 - CHESS / 2+i/2,
CHESS - i, CHESS - i);
}
}
}
对象的数据类型就是前面的类名
Chess chess = new Chess(chessX, chessY, color);
chess.drawChess(gr);
按顺序保存棋子对象
chessArr[count++] = chess;
label.setText("步数:"+count);
判断输赢
if (isWin() >= 5 || isLeftRight()>=5) {
if (winArr[chessY][chessX] == 1) {
drawWin("黑棋赢!");
} else if (winArr[chessY][chessX] == 2) {
drawWin("白棋赢!");
}
}
System.out.println("isWin() = " + isWin());
// printArr();
}
绘制字符串
public void drawWin(String msg){
//设置字体大小
gr.setFont(new Font("宋体",Font.BOLD,40));
gr.setColor(Color.RED);
gr.drawString(msg,400,400);
}
--------------------------------------------------------------------------------
四、在GameListener中编写判断输赢的方法
判断输赢:以最后一颗棋子为中心,搜索该棋子水平,垂直,左斜,右斜四个方向上的相连个数
public int isWin() {
记录棋子相连个数 int number = 0;
向左
for (int i = chessX; i >= 0; i--) {
if (winArr[chessY][i] == winArr[chessY][chessX]) {
number++;
} else {
终止当前循环 break;
}
}
向右
for (int i = chessX + 1; i < winArr.length; i++) {
if (winArr[chessY][i] == winArr[chessY][chessX]) {
number++;
} else {
break;
}
}
return number;
}
public int isLeftRight() {
记录棋子相连个数 int number = 0;
左上
for (int i = chessX,j=chessY; i >= 0 && j>=0; i--,j--) {
if (winArr[j][i] == winArr[chessY][chessX]) {
number++;
} else {
break;
}
}
右下
for(int i=chessX+1,j=chessY+1;i<winArr.length&&j<winArr.length;i++,j++){
if (winArr[j][i] == winArr[chessY][chessX]) {
number++;
} else {
break;
}
}
return number;
}
***打印二维数组
public void printArr() {
遍历二维数组的数据
for (int i = 0; i < winArr.length; i++) {
for (int j = 0; j < winArr[0].length; j++) {
System.out.print(winArr[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
1724

被折叠的 条评论
为什么被折叠?



