第一部分:启动面板
public class ChessGame{
public static void main(String[] args) {
new ChessJFrame().init();
}
}
第二部分:游戏界面
游戏逻辑、游戏面板,都写在这里面了
package chess;
import javax.sound.sampled.Clip;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class ChessJFrame extends JFrame implements MouseListener,ActionListener{
//菜单条
private JMenuBar jmb;
//菜单
private JMenu jm_game;
//菜单中的项
//开始新游戏
private JMenuItem jm_new_game;
//选择黑方先手 默认是红方先手
private JMenuItem jm_game_black;
//悔棋
private JMenuItem jm_regret_game;
//投降
private JMenuItem jm_give_game;
//退出游戏 结束系统进程
private JMenuItem jm_exit_game;
//帮助菜单 辅助功能
private JMenu jm_help;
//棋盘规则介绍
private JMenuItem jm_help_game;
//开始音乐特效
private JMenuItem jm_music_game;
//棋盘面板
private JLabel jlbChessBoard;
//棋子图片所在路劲
private String url = "D:/1.1/jdbc/test/test2/src/main/java/resource/";
//存放棋子信息
private ChessInformation[][] chessInfo = new chess.ChessInformation[10][9];
//窗口左顶点到棋盘的水平距离
private Integer gridLeftX = 60;
//窗口左顶点到棋盘的垂直距离
private Integer gridTopY = 60;
//棋盘水平网格大小
private Integer gridSizeX = 145/2;
//棋盘垂直网格大小
private Integer gridSizeY = 70;
//棋子大小
private Integer chessSize = 50;
//画落子指示器 点击棋子时赋值 repaint走子结束后赋值为null
private ChessInformation mapPointerMove;
//判断该那方走子
private int count = 0;
//存放点击棋子没移动前的信息
private ArrayList<chess.ChessInformation> list = new ArrayList<>();
private boolean flag = false;
private String red = "红";
private String black = "黑";
private String chessImg[][] = {
{"黑车", "黑马", "黑相", "黑士", "黑将", "黑士", "黑相", "黑马", "黑车"},
{"", "", "", "", "", "", "", "", ""},
{"", "黑炮", "", "", "", "", "", "黑炮", ""},
{"黑兵", "", "黑兵", "", "黑兵", "", "黑兵", "", "黑兵"},
{"", "", "", "", "", "", "", "", ""},
{"", "", "", "", "", "", "", "", ""},
{"红兵", "", "红兵", "", "红兵", "", "红兵", "", "红兵"},
{"", "红炮", "", "", "", "", "", "红炮", ""},
{"", "", "", "", "", "", "", "", ""},
{"红车", "红马", "红相", "红士", "红帅", "红士", "红相", "红马", "红车"}
};
//添加菜单栏 根据图片大小 设置窗口大小 添加棋子图片到面板上
public void init(){
jmb = new JMenuBar();
jm_game = new JMenu("游戏");
jm_game.setFont(new Font("微软雅黑", Font.PLAIN,12));//设置字体普通样式
jm_new_game = new JMenuItem();
jm_new_game = jm_game.add("新游戏");//设置jm_new_game的标签为"新游戏" 将"新游戏"添加到jm_game 菜单中
jm_new_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_new_game.addActionListener(this);
jm_new_game.setActionCommand("new");//给一个JButton设置一个属性的字符串值
jm_game_black = new JMenuItem();
jm_game_black = jm_game.add("黑方先手");
jm_game_black.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_game_black.addActionListener(this);
jm_game_black.setActionCommand("black");
jm_regret_game = new JMenuItem();
jm_regret_game = jm_game.add("悔棋");
jm_regret_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_regret_game.addActionListener(this);
jm_regret_game.setActionCommand("regret");
jm_give_game = new JMenuItem();
jm_give_game = jm_game.add("认输");
jm_give_game.setFont(new Font("微软雅黑",Font.PLAIN,12));//设置字体普通样式
jm_give_game.addActionListener(this);
jm_give_game.setActionCommand("give");
jm_game.addSeparator();
jm_exit_game = new JMenuItem();
jm_exit_game = jm_game.add("退出");
jm_exit_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_exit_game.addActionListener(this);
jm_exit_game.setActionCommand("exit");
jmb.add(jm_game);
jm_help = new JMenu("帮助");
jm_help.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_music_game = jm_help.add("音乐");
jm_music_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_music_game.addActionListener(this);
jm_music_game.setActionCommand("music");
jm_music_game = jm_help.add("音乐暂停");
jm_music_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_music_game.addActionListener(this);
jm_music_game.setActionCommand("musicStop");
jm_help_game = jm_help.add("关于");
jm_help_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
jm_help_game.addActionListener(this);
jm_help_game.setActionCommand("about");
jmb.add(jm_help);
this.setJMenuBar(jmb);
this.setVisible(true);
this.setBounds(300,0,700,800);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("中国象棋");
this.setResizable(false);//设置不可改变窗口大小
this.setLayout(null);//清空布局方式
chess();
}
//添加棋子图片到面板上
public void chess(){
//棋盘背景图
jlbChessBoard = new JLabel(new ImageIcon("D:/1.1/jdbc/test/test2/src/main/java/resource/chessboard.gif"));
jlbChessBoard.setBounds(0,0,692,764);
this.add(jlbChessBoard);
for (int i = 0; i < chessImg.length; i++) {//10先横排后竖排 先移动x后移y
for (int j = 0; j < chessImg[0].length; j++) {//9
JLabel label = new JLabel(new ImageIcon(url+chessImg[i][j]+".png"));
label.setBounds(60 +145/2 * j - 25,60 + i * 140/2 - 25,50,50);
jlbChessBoard.add(label);
label.addMouseListener(this);
chessInfo[i][j] = new chess.ChessInformation(i,j,chessImg[i][j],label);
}
}
jm_game_black.setEnabled(true);
mapPointerMove = null;
this.count = 0;
this.repaint();
}
@Override
public void mouseClicked(MouseEvent e) {
//获取事件源 鼠标点击的信息
JLabel source = (JLabel) e.getSource();
for (int i = 0; i < chessImg.length; i++) {
for (int j = 0; j < chessImg[0].length; j++) {
if (source == chessInfo[i][j].getJlbChess()){//点击棋盘
if (!chessInfo[i][j].getChessName().equals("")){//点击棋子
jm_game_black.setEnabled(false);//关闭先手按钮
//符合移动条件 吃子
if (list.size() != 0 && isAboutMove(list.get(0), chessInfo[i][j])){
if (chessInfo[i][j].getChessName().contains("帅") || chessInfo[i][j].getChessName().contains("将")){
this.success(chessInfo[i][j].getChessName().substring(1));
return;
}
ChessInformation oldChessInfo = list.get(0);
chessInfo[i][j].getJlbChess().setIcon(null);
chessInfo[i][j].setRow(i);
chessInfo[i][j].setColumn(j);
chessInfo[i][j].setChessName(oldChessInfo.getChessName());
chessInfo[i][j].getJlbChess().setIcon(oldChessInfo.getJlbChess().getIcon());
//清空原始位置信息
oldChessInfo.setChessName("");
oldChessInfo.getJlbChess().setIcon(null);
count++;
flag = false;
list.clear();
mapPointerMove = null;
if (chessInfo[i][j].getChessName().equals("帅") || chessInfo[i][j].getChessName().equals("将")){
this.success(chessInfo[i][j].getChessName().substring(1));
}
}
//红黑选择 将点击的棋子信息放入集合中
if (count % 2==0 && chessInfo[i][j].getChessName().contains(red)){
mapPointerMove = chessInfo[i][j];
this.repaint();
if (list.size()==0){
list.add(chessInfo[i][j]);
}else {
list.set(0,chessInfo[i][j]);
}
}
if (count % 2==1 && chessInfo[i][j].getChessName().contains(black)){
mapPointerMove = chessInfo[i][j];
this.repaint();
if (list.size()==0){
list.add(chessInfo[i][j]);
}else {
list.set(0,chessInfo[i][j]);
}
}
}else {
//点击为空 移动棋子 或者 吃子
ChessInformation oldChessInfo = new chess.ChessInformation();
//移动棋子
if (list.size() != 0){
oldChessInfo = list.get(0);
flag = isAboutMove(oldChessInfo, chessInfo[i][j]);
}
if(flag){
//走棋成功 替换信息 图片
chessInfo[i][j].setRow(i);
chessInfo[i][j].setColumn(j);
chessInfo[i][j].setChessName(oldChessInfo.getChessName());
chessInfo[i][j].getJlbChess().setIcon(oldChessInfo.getJlbChess().getIcon());
//清空原始位置信息
oldChessInfo.setChessName("");
oldChessInfo.getJlbChess().setIcon(null);
count++;
flag = false;
list.clear();
mapPointerMove = null;
}
//每移动一个棋子 遍历一遍查看将帅信息
boolean foreach = foreach(chessInfo[i][j].getChessName());
if (foreach) return;
}
}
}
}
}
//判断是否符合走子规则
private boolean isAboutMove(chess.ChessInformation oldInfo, chess.ChessInformation newInfo) {
int oldRow = oldInfo.getRow();
int oldColumn = oldInfo.getColumn();
int newRow = newInfo.getRow();
int newColumn = newInfo.getColumn();
//不能吃己方 移动的棋子,与棋子移动的坐标上棋子信息
if (
oldInfo.getChessName().contains("红") && newInfo.getChessName().contains("红") ||
oldInfo.getChessName().contains("黑") && newInfo.getChessName().contains("黑")
) return false;
//不能原地移动
if (oldRow == newRow && oldColumn == newColumn) return false;
//将帅
if (oldInfo.getChessName().contains("帅") || oldInfo.getChessName().contains("将") ) {
//帅不能出九宫
if (newRow > 2 && newRow < 7 || newColumn < 3 || newColumn > 5) return false;
boolean b = Math.abs((newRow - oldRow)) > 1 || Math.abs(newColumn - oldColumn) > 1;
if (b) return false;
boolean b1 = (newRow - oldRow) * (newColumn - oldColumn) != 0;
if (b1) return false;
} else if (oldInfo.getChessName().contains("士")) {//仕
if (newRow > 2 && newRow < 7 || newColumn < 3 || newColumn > 5) return false;
if (Math.abs((newRow - oldRow)) > 1 || Math.abs(newColumn - oldColumn) > 1) return false;
if ((newRow - oldRow) * (newColumn - oldColumn) == 0) return false;
} else if (oldInfo.getChessName().contains("相")) {
//不能越界
if (oldInfo.getChessName().contains("黑")) {
if (newRow > 4) return false;
} else if (newRow < 5) return false;
if (Math.abs(newRow - oldRow) != 2 || Math.abs(newColumn - oldColumn) != 2) {
return false;
}
//是否堵象眼
if (!this.chessInfo[Math.min(oldRow, newRow) + 1][Math.min(oldColumn, newColumn) + 1].getChessName().equals("")) {
return false;
}
} else if (oldInfo.getChessName().contains("马")) {
if (Math.abs(newRow - oldRow) * Math.abs(newColumn - oldColumn) != 2) return false;
if (newRow - oldRow == -2) {
if (!this.chessInfo[oldRow - 1][oldColumn].getChessName().equals("")) return false;
}
if (newRow - oldRow == 2) {
if (!this.chessInfo[oldRow + 1][oldColumn].getChessName().equals("")) return false;
}
if (newColumn - oldColumn == -2) {
if (!this.chessInfo[oldRow][oldColumn - 1].getChessName().equals("")) return false;
}
if (newColumn - oldColumn == 2) {
if (!this.chessInfo[oldRow][oldColumn + 1].getChessName().equals("")) return false;
}
} else if (oldInfo.getChessName().contains("车")) {
if ((newRow - oldRow) * (newColumn - oldColumn) != 0) return false;
if (newColumn == oldColumn) {
int min = Math.min(newColumn, oldColumn);
int max = Math.max(newColumn, oldColumn);
for (int i = min + 1; i < max; i++) {
if (!this.chessInfo[oldRow][i].getChessName().equals("")) return false;
}
} else if (newRow == oldRow) {
int min = Math.min(newRow, oldRow);
int max = Math.max(newRow, oldRow);
for (int i = min + 1; i < max; i++) {
if (!this.chessInfo[i][oldColumn].getChessName().equals("")) return false;
}
}
} else if (oldInfo.getChessName().contains("炮")) {//炮
if ((newRow - oldRow) * (newColumn - oldColumn) != 0) return false;
int count =0;
if (newColumn == oldColumn) {
int min = Math.min(oldRow, newRow);
int max = Math.max(oldRow, newRow);
for (int row = min + 1; row < max; row++) {
if (!this.chessInfo[row][newColumn].getChessName().equals("")) {
count++;
}
}
}
if (newRow == oldRow) {
int min = Math.min(oldColumn, newColumn);
int max = Math.max(oldColumn, newColumn);
for (int column = min + 1; column < max; column++) {
if (!this.chessInfo[newRow][column].getChessName().equals("")) {
count++;
}
}
}
if (count>1){
return false;
} else if (count == 1){//中间有棋子
if (this.chessInfo[newRow][newColumn].getChessName().equals("")) return false;
} else {//途中没有棋子,不能吃子
if (!this.chessInfo[newRow][newColumn].getChessName().equals("")) return false;
}
}
else if(oldInfo.getChessName().contains("兵")){
if ((newRow - oldRow) * (newColumn - oldColumn) !=0) return false; //不能斜着走
if (Math.abs(newRow - oldRow) > 1 || Math.abs(newColumn - oldColumn) > 1) return false; //步数为1
if (oldInfo.getChessName().contains("黑")){//上方棋子
if (newRow < 4){//不过河不左右移动
if (newColumn - oldColumn != 0) return false;
}
if (newRow - oldRow == -1) return false; //不得撤退
}else {
if (oldRow >= 5){
if (newColumn - oldColumn != 0) return false;
}
return newRow - oldRow != 1;
}
}
return true;
}
//画出行列 以及 落子指示器
@Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2D = (Graphics2D)g;
g2D.setColor(Color.GREEN);
for (int row = 0; row < 10; row++) {//描绘行信息 0-9
g2D.drawString(String.valueOf(row),35, row * 70 + 115);
}
for (int column = 0; column < 9; column++) {//描绘列信息 0-8
g2D.drawString(String.valueOf(column),column * 145/2 + 60,80);
}
if (mapPointerMove!=null) {
int x = this.gridLeftX + mapPointerMove.getColumn() * gridSizeX + 8;
int y = this.gridTopY + mapPointerMove.getRow() * gridSizeY + 53;
int x1 = x - this.chessSize / 2;
int y1 = y - this.chessSize / 2;
g2D.setStroke(new BasicStroke(3.5f));
g2D.drawLine(x1, y1, x1, y1 + chessSize / 4);//以四点为基 向上下延伸划线
g2D.drawLine(x1, y1, x1 + chessSize / 4, y1);
g2D.drawLine(x1 + chessSize, y1, x1 + chessSize * 3 / 4, y1);
g2D.drawLine(x1 + chessSize, y1, x1 + chessSize, y1 + chessSize / 4);
g2D.drawLine(x1, y1 + chessSize, x1, y1 + chessSize * 3 / 4);
g2D.drawLine(x1, y1 + chessSize, x1 + chessSize / 4, y1 + chessSize);
g2D.drawLine(x1 + chessSize, y1 + chessSize, x1 + chessSize, y1 + chessSize * 3 / 4);
g2D.drawLine(x1 + chessSize, y1 + chessSize, x1 + chessSize * 3 / 4, y1 + chessSize);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
public void success(String general){//黑将 红帅
if (general.contains("帅")){//恭喜,黑方获胜
JOptionPane.showMessageDialog(null,"恭喜,黑方获胜!");
this.newGame();
return;
}else if (general.contains("将")) {
JOptionPane.showMessageDialog(null,"恭喜,红方获胜!");
this.newGame();
return;
}
if (general.contains("红")){//恭喜,黑方获胜
JOptionPane.showMessageDialog(null,"恭喜,黑方获胜!");
}else {
JOptionPane.showMessageDialog(null,"恭喜,红方获胜!");
}
this.newGame();
}
public void newGame() {
this.getContentPane().removeAll();
this.repaint();
this.chess();
}
public void regret() {
}
public void give() {
JOptionPane.showMessageDialog(null,"已投降!");
this.newGame();
}
// 避免棋子图片覆盖
//点击某个按钮后 执行相应的操作
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();//获得被点击事件
if ("new".equals(command)) this.newGame();
if ("regret".equals(command)) this.regret();
if ("give".equals(command)) this.give();
if ("exit".equals(command)) System.exit(0);
if ("about".equals(command)) {
JOptionPane.showMessageDialog(this,"请上网查阅","提示",JOptionPane.INFORMATION_MESSAGE);
}
if ("music".equals(command)){
MusicTest.clip.loop(Clip.LOOP_CONTINUOUSLY);
}
if ("musicStop".equals(command)){
MusicTest.clip.stop();
}
if("black".equals(command)){
red = "黑";
black = "红";
}
}
//遍历将帅的情况
public boolean foreach(String chessName){
ChessInformation oldRow = null;
ChessInformation newRow = null;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 9; j++) {
//找到将帅的棋子信息
if (chessInfo[i][j].getChessName().contains("帅")){
oldRow = chessInfo[i][j];
}else if (chessInfo[i][j].getChessName().contains("将")){
newRow = chessInfo[i][j];
}
//找到将帅
if (newRow != null && oldRow != null){
//当两个棋子在同一列 判断中间是否有棋子 如果没棋子 结束游戏
if (newRow.getColumn() == oldRow.getColumn()) {
int count = 0;
int min = Math.min(oldRow.getRow(), newRow.getRow());
int max = Math.max(oldRow.getRow(), newRow.getRow());
for (int row = min + 1; row < max; row++) {
if (!this.chessInfo[row][oldRow.getColumn()].getChessName().equals("")) {
count++;
}
}
//正在移动的棋子信息
if (count == 0) {
this.success(chessName);
return true;
}
}else {
return false;
}
}
}
}
return false;
}
}
第三部分:实体类
package chess;
import javax.swing.*;
public class ChessInformation {
private int row;
private int column;
private String chessName;
private JLabel jlbChess;
public ChessInformation() {
}
public ChessInformation(int row, int column, String chessName, JLabel jlbChess) {
this.row = row;
this.column = column;
this.chessName = chessName;
this.jlbChess = jlbChess;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return column;
}
public void setColumn(int column) {
this.column = column;
}
public String getChessName() {
return chessName;
}
public void setChessName(String chessName) {
this.chessName = chessName;
}
public JLabel getJlbChess() {
return jlbChess;
}
public void setJlbChess(JLabel jlbChess) {
this.jlbChess = jlbChess;
}
@Override
public String toString() {
return "chessInformation{" +
"row=" + row +
", column=" + column +
", chessName='" + chessName + '\'' +
", jlbChess=" + jlbChess +
'}';
}
}
第四部分: 背景音乐
这一部分需要注意音频必须是wav格式 请前往格式转换网站转化格式
https://houzi8.com/tools/convert
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
public class MusicTest{
static Clip clip = new Clip() {
@Override
public void loop(int count) {
try {
//这里面放 绝对路径,音频必须是wav格式,用音频转换软件 把mp3 转成wav格式
File musicPath = new File("D:\\1.1\\jdbc\\test\\test2\\src\\main\\java\\bgm\\jf49w-2xrtf.wav");
if(musicPath.exists()) {
//AudioSystem 通过类加载器,将音频播放 音频输入流
AudioInputStream audioInput = AudioSystem.getAudioInputStream(musicPath);
//获得可用于播放音频
clip = AudioSystem.getClip();
clip.open(audioInput);
//FloatControl.Type.MASTER_GAIN
// 正增益放大(提升)信号的音量,负增益衰减(削减)它。 增益设置默认值为0.0 dB
FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(1.0f);//设置音量,范围为 -60.0f 到 6.0f
clip.start();
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
else {}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
@Override
public void open(AudioFormat format, byte[] data, int offset, int bufferSize) throws LineUnavailableException {
}
@Override
public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
}
@Override
public int getFrameLength() {
return 0;
}
@Override
public long getMicrosecondLength() {
return 0;
}
@Override
public void setFramePosition(int frames) {
}
@Override
public void setMicrosecondPosition(long microseconds) {
}
@Override
public void setLoopPoints(int start, int end) {
}
@Override
public void drain() {
}
@Override
public void flush() {
}
@Override
public void start() {
}
@Override
public void stop() {
}
@Override
public boolean isRunning() {
return false;
}
@Override
public boolean isActive() {
return false;
}
@Override
public AudioFormat getFormat() {
return null;
}
@Override
public int getBufferSize() {
return 0;
}
@Override
public int available() {
return 0;
}
@Override
public int getFramePosition() {
return 0;
}
@Override
public long getLongFramePosition() {
return 0;
}
@Override
public long getMicrosecondPosition() {
return 0;
}
@Override
public float getLevel() {
return 0;
}
@Override
public Line.Info getLineInfo() {
return null;
}
@Override
public void open() throws LineUnavailableException {
}
@Override
public void close() {
}
@Override
public boolean isOpen() {
return false;
}
@Override
public Control[] getControls() {
return new Control[0];
}
@Override
public boolean isControlSupported(Control.Type control) {
return false;
}
@Override
public Control getControl(Control.Type control) {
return null;
}
@Override
public void addLineListener(LineListener listener) {
}
@Override
public void removeLineListener(LineListener listener) {
}
};
}