游戏分为三部分
- 界面
- 绘制棋盘背景
- 绘制棋子
- 逻辑规则
- 移动规则
- 吃子逻辑
- 回合结束换阵营
MainFrame类
import javax.swing.*;
public class MainFrame {
public static void main(String[] args) {
JFrame jfm = new JFrame();
jfm.setSize(800,800);//设置大小
jfm.setLocationRelativeTo(null);//居中
jfm.setResizable(false);//不许窗口更改
jfm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭
jfm.add(new GamePanel());//添加游戏面板
//展示窗口
jfm.setVisible(true);
}
}
GamePanel类
实现
- 绘制棋子功能
- 移动棋字功能
- 回合交替功能
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
public class GamePanel extends JPanel {
private Chess[] chesses = new Chess[32];//保存所有棋子
private Chess selectChess;//当前选中棋子
private int culPlayer = 1;//识别阵营,默认红方先走
public GamePanel(){
/*使创建棋子先执行*/
createChesses();
//添加鼠标点击事件
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("点击位置的x坐标:"+e.getX()+",y坐标:"+e.getY());
Point p = Chess.getPointFromXY(e.getX(),e.getY());
System.out.println("点击位置的网格坐标对象为p::"+p);
if(selectChess == null){
//第一次选择
selectChess = getChessByP(p);
if (selectChess != null && selectChess.getPlayer() != culPlayer){
selectChess = null;//初始点击黑棋无效
}
}else {
//重新选择,移动,吃子
Chess c = getChessByP(p);
if (c != null){
//第n次点击的时候有棋子
if (c.getPlayer() == (selectChess.getPlayer())){
//同阵营重新选择棋子
selectChess = c;
}else{
//吃子
//1.删除被吃掉的棋子
//2.修改要移动棋子的坐标
System.out.println("吃子");
if (selectChess.isAbleMove(p, GamePanel.this)){
chesses[c.getIndex()] = null;//删除
selectChess.setP(p);
overMyTurn();
}
}
}else{
//第n次点击的时候没有棋子
//移动
System.out.println("移动");
if (selectChess.isAbleMove(p, GamePanel.this)){
selectChess.setP(p);
overMyTurn();
}
}
}
System.out.println("点击棋子对象为selectChess::"+selectChess);
//刷新棋盘,即重新执行paint方法
repaint();
}
});
}
/*结束当前回合*/
private void overMyTurn(){
culPlayer = culPlayer == 1 ? 0 : 1;
selectChess = null;
}
/*根据网格对象坐标p查找棋子
*判断棋子坐标是否重合:吃子
* */
public Chess getChessByP(Point p){
for (Chess item : chesses){
if (item != null && item.getP().equals(p)){
return item;
}
}
return null;
}
/*创建棋子*/
private void createChesses(){
//定义一个棋子数组
//一个格子80
String[] names = {"che", "ma", "xiang", "shi", "jiang", "shi", "xiang", "ma", "che", "pao", "pao", "bing", "bing", "bing", "bing", "bing"};
//定义一个棋子网格坐标数组
int xs[] = {1,2,3,4,5,6,7,8,9,2,8,1,3,5,7,9};
for (int i = 0; i < names.length; i++){
/* Chess c = new Che(0,xs[i]);//创建黑棋对象*/
/*c.setName(names[i]);//获得对应棋子
c.setP(ps[i]);//获得棋子网格坐标
c.setPlayer(0);//黑棋阵营*/
Chess c = ChessFactory.create(names[i],0,xs[i]);//创建黑棋对象
c.setIndex(i);
chesses[i] = c;
}
for (int i = 0; i < names.length; i++){
Chess c = ChessFactory.create(names[i],1,xs[i]);//创建红棋对象
/* c.setName(names[i]);//获得对应棋子
c.setP(ps[i]);//获得棋子网格坐标
c.setPlayer(1);//红棋阵营*/
c.reserve();
c.setIndex(i+16);
chesses[c.getIndex()]=c;//将棋子保存在数组里
}
}
/*绘制棋子*/
private void drawChesses(Graphics g){
for (Chess item : chesses){
if (item != null){
item.draw(g,this);
}
}
}
@Override
public void paint(Graphics g) {//Graphics:绘制类
super.paint(g);//清除原来的痕迹
/*File.separator:路径分隔符,相当于“\”*/
String bgPath = "Pic" + File.separator + "qipan.png";//准备图片路径
/*Toolkit.getDefaultToolkit():获取Toolkit的实例*/
Image qipan = Toolkit.getDefaultToolkit().getImage(bgPath);
//使背景图片铺满整个窗口
g.drawImage(qipan, 0, 0, 600, 600, this);
drawChesses(g);
if (selectChess != null){
selectChess.drawRect(g,this);
}
}
}
Chess类
用抽象类+简单工厂模式去实现
定义一个棋子工厂生产棋子
/*简单工厂模式*/
public class ChessFactory {
private ChessFactory() {
}
public static Chess create(String name, int player, int px) {
if ("jiang".equals(name)) {
return new Jiang(player, px);
} else if ("shi".equals(name)) {
return new Shi(player, px);
} else if ("xiang".equals(name)) {
return new Xiang(player, px);
} else if ("ma".equals(name)) {
return new Ma(player, px);
} else if ("che".equals(name)) {
return new Che(player, px);
} else if ("pao".equals(name)) {
return new Pao(player, px);
}else if ("bing".equals(name)){
return new Bing(player, px);
}
return null;
}
}
棋子移动过程中用到的方法
import javax.swing.*;
import java.awt.*;
import java.io.File;
public abstract class Chess {
private String name;
private int x;
private int y;//棋子实际坐标
protected Point p;//棋子网格坐标
private Point initP;//棋子网格坐标初始位置,不可改变
private String suffix = ".png";//后缀名
private static final int SIZE =45;//棋子直径
private static final int XMARGIN = 60;//x轴外边距
private static final int YMARGIN = 30;//y轴外边距
private static final int SPACE = 60;//棋子间距
protected int player;//阵营:1,红 0:黑
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
private int index;//保存每个棋子的索引位置
/*绘制棋子*/
public void draw(Graphics g , JPanel panel){
String PathB = "Pic" + File.separator + player + name + suffix;
Image ImgB = Toolkit.getDefaultToolkit().getImage(PathB);
g.drawImage(ImgB,x,y, SIZE, SIZE, panel);
}
/*给选中棋子画边框*/
public void drawRect(Graphics g, GamePanel gamePanel) {
String PathC = "Pic" + File.separator + "selected" + suffix;
Image ImgC = Toolkit.getDefaultToolkit().getImage(PathC);
g.drawImage(ImgC,x-5,y-5, gamePanel);
}
//计算棋子绘制坐标
public void calXY() {
x = XMARGIN - SIZE / 2 + SPACE * (p.x - 1);
y = YMARGIN - SIZE / 2 + SPACE * (p.y - 1);
}
/*根据监听器坐标计算网格坐标*/
public static Point getPointFromXY(int x, int y) {
Point p = new Point();
p.x = (x - XMARGIN + SIZE / 2) / SPACE + 1;
p.y = (y - YMARGIN + SIZE / 2) / SPACE + 1;
if (p.x < 1 || p.x > 9 || p.y < 1 || p.y > 10) {
return null;
}
return p;
}
/*计算翻转坐标*/
public void reserve(){
/* x = XMARGIN - SIZE / 2 + ((10-(p.x) - 1) * SPANCE);
y = YMARGIN - SIZE / 2 + ((11-(p.y) - 1) * SPANCE);*/
p.x = 10 - p.x;
p.y = 11 - p.y;
initP = p;
calXY();
}
/**
* 判断选中棋子初始是上半棋盘还是下半棋盘
* 1:上
* 2:下
* */
public int isUpOrDown(){
if (initP.y < 6 ){
//上面
return 1;
}else if (initP.y > 5){
//下面
return 2;
}
return 0;
}
/**
* 判断目标坐标是否在王宫内
* */
public boolean isHome(Point tp) {
if (tp.x < 4 || tp.x > 6) {
return false;
}
int upOrDown = isUpOrDown();
if (upOrDown == 1) {
//上面
if (tp.y > 3 || tp.y < 0) {
return false;
}
} else if (upOrDown == 2) {
//下面
if (tp.y > 10 || tp.y < 8) {
return false;
}
}
return true;
}
/**
* 判断是走直线走斜线或者都不是
* 1:正斜线
* 2:走y方向的直线
* 3:走x方向的直线
* 0:x方向日字
* -1:y方向日字
* -2:都不是
* */
public int line(Point tp){
if (p.y == tp.y){
//x
return 3;//x直线
}else if (p.x == tp.x){
//y
return 2;//y直线
}else if (Math.abs(p.x - tp.x) == Math.abs(p.y - tp.y)){
return 1;//走斜线
}else{
//走日字
//两种情况:1.x方向日字 2.y方向日字
if (Math.abs(p.x - tp.x) == 2 && Math.abs(p.y - tp.y) == 1){
return 0;
}else if (Math.abs(p.x - tp.x) == 1 && Math.abs(p.y - tp.y) == 2){
return -1;
}
}
return -2;
}
/**
* 计算起点到目标点之间的步数
* */
public int getStep(Point tp){
int line = line(tp);
if (line == 3){
//x
return Math.abs(p.x - tp.x);
}else if (line == 2 || line == 1){
//y
//正斜线
return Math.abs(p.y - tp.y);
}
return 0;
}
/*判断目标点是否过河*/
public boolean isOverRiver(Point tp){
int upOrDown = isUpOrDown();
if (upOrDown == 1){
//上面
if (tp.y < 6){
return false;
};
}else if (upOrDown == 2){
//下面
if (tp.y > 5){
return false;
};
}
return true;
}
/*查看马和象要移动到目标点是否蹩脚*/
public boolean isBieJiao(Point tp, GamePanel gamePanel){
Point center = new Point();//棋子中心点
if ("xiang".equals(name)){
//象
center.x = (p.x + tp.x)/2;
center.y = (p.y + tp.y)/2;
return gamePanel.getChessByP(center) != null;
}else if ("ma".equals(name)){
//马
//求中心点
int line = line(tp);
if (line == 0){
//x
center.x = (p.x + tp.x) / 2;
center.y = p.y;
}else if (line == -1){
//y
center.x = p.x;
center.y = (p.y + tp.y) / 2;
}
return gamePanel.getChessByP(center) != null;
}
return true;
}
/*计算起点到目标坐标之间棋子数量
* 不包括起点与目标点
* */
public int getCount(Point tp, GamePanel gamePanel){
int start = 0;
int end = 0;
int count = 0;//统计棋子数量
int line = line(tp);
Point np = new Point();
if (line == 2){
//y轴
np.x = tp.x;
if (tp.y > p.y){
//从上往下
start = p.y + 1;
end = tp.y;
}else {
//从下往上
start = tp.y + 1;
end = p.y;
}
for(int i = start;i < end;i++){
np.y = i;
if (gamePanel.getChessByP(np) != null){
count++;
}
}
}else if (line == 3){
//x轴
np.y = tp.y;
if (tp.x > p.x){
//从左往右
start = p.x + 1;
end = tp.x;
}else {
//从右往左
start = tp.x + 1;
end = p.x;
}
for(int i = start;i < end;i++){
np.x = i;
if (gamePanel.getChessByP(np) != null){
count++;
}
}
}
System.out.println("棋子总数为:"+count);
return count;
}
/*判断兵是否前进*/
public boolean isForward(Point tp){
//分为棋盘上半面和下半面两种情况
int upDown = isUpOrDown();
if (upDown == 1){
//上
if (tp.y > p.y){
return true;
}
}else if (upDown == 2){
//下
if (tp.y < p.y){
return true;
}
}
return false;
}
/*判断是否后退*/
/*判断兵是否前进*/
public boolean isBack(Point tp){
//分为棋盘上半面和下半面两种情况
int upDown = isUpOrDown();
if (upDown == 1){
//上
if (tp.y < p.y){
return true;
}
}else if (upDown == 2){
//下
if (tp.y > p.y){
return true;
}
}
return false;
}
/*判断棋子是否可以移动到对应位置*/
public abstract boolean isAbleMove(Point tp, GamePanel gamePanel);
public Chess(String name, int player, Point p) {
this.name = name;
this.player = player;
setP(p);
}
public void setName(String name) {
this.name = name;
}
public int getPlayer() {
return player;
}
public void setPlayer(int player) {
this.player = player;
}
public void setP(Point p) {
this.p = (Point) p.clone();//复制p对象,否则另一半棋子依旧指向原坐标
if (initP == null){
initP = this.p;
}
calXY();
}
public Point getP() {
return p;
}
@Override
public String toString() {
return "Chess{" +
"name='" + name + '\'' +
", x=" + x +
", y=" + y +
", p=" + p +
", initP=" + initP +
", suffix='" + suffix + '\'' +
", player='" + player + '\'' +
'}';
}
}
最后利用棋子工厂生产各类棋子:如车类
import com.yu.Main.GamePanel;
import java.awt.*;
public class Che extends Chess{
public Che(int player, Point p) {
super("che", player, p);
}
public Che(int player, int px) {
this(player, new Point(px,1));
}
@Override
public boolean isAbleMove(Point tp, GamePanel gamePanel) {
return line(tp) > 1 && getCount(tp, gamePanel) == 0;
}
}
运行截图: