中国象棋小项目

游戏分为三部分

  • 界面
    • 绘制棋盘背景
    • 绘制棋子
  • 逻辑规则
    • 移动规则
    • 吃子逻辑
    • 回合结束换阵营

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;
    }
}

运行截图:
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月色夜雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值