根据http://blog.csdn.net/cnlht/article/details/8176130衍生。增加了悔棋只可毁一次。
一、先设计棋子类
棋子类要包括下的位置和棋子的颜色,即x、y坐标与Color。另外,还要设置好棋子的大小,即直径。
import java.awt.Color;
public class Point {
private int x;
private int y;
private Color color;
public static final int DIAMETER = 30; //直径
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Point(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
}
二、设计棋盘类
继承自JPanel,接口MouseListener来监听鼠标事件。
JPanel 是 Java图形用户界面(GUI)工具包swing中的面板容器类,包含在javax.swing 包中,是一种轻量级容器,可以加入到JFrame窗体中。JPanel默认的布局管理器是FlowLayout((从左到右诸行排列)),其自身可以嵌套组合,在不同子容器中可包含其他组件(component),如JButton、JTextArea、JTextField 等,功能是对对窗体上的这些控件进行组合。
1、全局变量
public static final int MARGIN = 20; //边距
public static final int GRID_SPAN = 35; //网络间隔
public static final int ROWS = 15; //棋盘行数
public static final int COLS = 15; //棋盘列数
public static final Color DEFAULT_COLOR = Color.RED; //无悔棋默认为红色
private Point[] chessList = new Point[(ROWS + 1) * (COLS + 1)]; //初始化每个数组元素为null
private boolean isBlack = true; //默认执黑先行
private boolean gameOver = false; //游戏是否结束
private Color regretColor= DEFAULT_COLOR; //悔棋时候的棋子色,无悔棋默认为红色
private int chessCount; //当前棋盘棋子的个数
private int xIndex, yIndex; //当前落子的索引
2、构造函数
public ChessBoard() {
setBackground(Color.orange); //设置背景色为桔黄色
addMouseListener(this);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
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;
//游戏结束不能下;落在棋盘外不能下;位置上已有棋子不能下
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)); //光标为手掌
}
}
});
}
3、绘制棋盘与棋子paintComponent
super.paintComponent(g)是父类JPanel里的方法,会把整个面板用背景色重画一遍,起到清屏的作用。在swing控件中,paint方法会依次调用paintcomponent, paintborder, paintchildren三个方法,后两者一般默认即可,所以swing编程时,如果继承jcomponent或者其子类,要覆盖paintcomponent而不是paint方法。
paint :绘制容器。
paintComponents : 绘制此容器中的每个组件。
由此不难看出,二者就是房子与家具的关系。
在java里设置组件的属性后会导致重绘,只不过由于这个重绘事件被放在事件派发线程里,因此随后调用的堵塞动作会导致事件派发线程被Idle,要避免这种情况,应该将这个堵塞动作放到另外的线程里面完成。
repaint()是触发重绘动作,当调用repaint()后,会通知repaintManager增加一个重绘区域,repaintManager在一定条件下会合并一些重绘区域,然后派发一个绘制动作到事件派发线程(EventQueue)。事件派发线程执行到这个绘制事件时,就会调用组件的paint(),在paint()方法里会先调用update来将重绘区域清空(默认情况下是填充白色),然后再调用paintcomponent()来绘制自身,最后调用paintChildren来绘制所有的子。具体流程可以参考JComponent里的paint()方法
如果super,会先调用了super.paintComponent进行界面重绘,再继续绘制自写函数里的东西。如果不调用父类的方法,则直接用重写函数里的内容进行重绘。
/**
* 绘制
*/
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics); //画棋盘
/*//获得窗口的宽度与高度
int FWidth = getWidth();
int FHeight = getHeight();*/
//画网格线
for (int i = 0;i <= ROWS; i++) {
graphics.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS * GRID_SPAN, MARGIN + i * GRID_SPAN);
}
for (int j = 0;j <= COLS; j++) {
graphics.drawLine(MARGIN + j * GRID_SPAN, MARGIN, MARGIN + j * GRID_SPAN, MARGIN + ROWS * GRID_SPAN);
}
//画棋子
for (int i = 0;i < chessCount; i++) {
//网格交叉点坐标
int xPos = (int) (chessList[i].getX() * GRID_SPAN + MARGIN);
int yPos = (int) (chessList[i].getY() * GRID_SPAN + MARGIN);
Color colorTemp = chessList[i].getColor();
graphics.setColor(colorTemp); //设置颜色
RadialGradientPaint paint;
if (colorTemp == Color.black) {
//前两个参数为圆心,第三个为