下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。
1. 项目结构
/src/main/java/com/example/chinesechess/
├── MainAbilitySlice.java // 主界面逻辑
├── ChessView.java // 游戏视图和逻辑
├── ChessPiece.java // 棋子类
└── resources/
├── base/
│ ├── layout/
│ │ └── ability_main.xml // 布局文件
│ └── graphic/
│ └── board_bg.xml // 棋盘背景
2. 实现代码
ChessPiece.java (棋子类)
package com.example.chinesechess;
public class ChessPiece {
public static final int RED = 0;
public static final int BLACK = 1;
private int type; // 棋子类型
private int color; // 棋子颜色
private int row; // 行
private int col; // 列
public ChessPiece(int type, int color, int row, int col) {
this.type = type;
this.color = color;
this.row = row;
this.col = col;
}
// 棋子类型常量
public static final int GENERAL = 0; // 将/帅
public static final int ADVISOR = 1; // 士
public static final int ELEPHANT = 2; // 象
public static final int HORSE = 3; // 马
public static final int CHARIOT = 4; // 车
public static final int CANNON = 5; // 炮
public static final int SOLDIER = 6; // 兵/卒
// getter和setter方法
public int getType() {
return type;
}
public int getColor() {
return color;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
// 获取棋子名称
public String getName() {
String[] redNames = {"帅", "仕", "相", "马", "车", "炮", "兵"};
String[] blackNames = {"将", "士", "象", "马", "车", "炮", "卒"};
return color == RED ? redNames[type] : blackNames[type];
}
}
ChessView.java (游戏视图和逻辑)
package com.example.chinesechess;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.agp.components.AttrSet;
import ohos.multimodalinput.event.TouchEvent;
import java.util.ArrayList;
import java.util.List;
public class ChessView extends Component implements Component.DrawTask {
private static final int ROWS = 10; // 棋盘行数
private static final int COLS = 9; // 棋盘列数
private Paint linePaint; // 棋盘线画笔
private Paint redPaint; // 红方棋子画笔
private Paint blackPaint; // 黑方棋子画笔
private Paint textPaint; // 文字画笔
private Paint selectedPaint; // 选中状态画笔
private List<ChessPiece> pieces; // 棋子列表
private ChessPiece selectedPiece; // 当前选中的棋子
private int currentPlayer = ChessPiece.RED; // 当前玩家
public ChessView(Context context) {
super(context);
init();
}
public ChessView(Context context, AttrSet attrSet) {
super(context, attrSet);
init();
}
private void init() {
linePaint = new Paint();
linePaint.setColor(new Color(0xFF000000));
linePaint.setStrokeWidth(2);
redPaint = new Paint();
redPaint.setColor(new Color(0xFFFF0000));
redPaint.setStyle(Paint.Style.FILL_STYLE);
blackPaint = new Paint();
blackPaint.setColor(new Color(0xFF000000));
blackPaint.setStyle(Paint.Style.FILL_STYLE);
textPaint = new Paint();
textPaint.setColor(new Color(0xFFFFFFFF));
textPaint.setTextSize(40);
textPaint.setTextAlign(Paint.Align.CENTER);
selectedPaint = new Paint();
selectedPaint.setColor(new Color(0x6600FF00));
selectedPaint.setStyle(Paint.Style.FILL_STYLE);
initPieces();
addDrawTask(this);
setTouchEventListener(this::onTouchEvent);
}
private void initPieces() {
pieces = new ArrayList<>();
// 初始化红方棋子
pieces.add(new ChessPiece(ChessPiece.CHARIOT, ChessPiece.RED, 9, 0));
pieces.add(new ChessPiece(ChessPiece.HORSE, ChessPiece.RED, 9, 1));
pieces.add(new ChessPiece(ChessPiece.ELEPHANT, ChessPiece.RED, 9, 2));
pieces.add(new ChessPiece(ChessPiece.ADVISOR, ChessPiece.RED, 9, 3));
pieces.add(new ChessPiece(ChessPiece.GENERAL, ChessPiece.RED, 9, 4));
pieces.add(new ChessPiece(ChessPiece.ADVISOR, ChessPiece.RED, 9, 5));
pieces.add(new ChessPiece(ChessPiece.ELEPHANT, ChessPiece.RED, 9, 6));
pieces.add(new ChessPiece(ChessPiece.HORSE, ChessPiece.RED, 9, 7));
pieces.add(new ChessPiece(ChessPiece.CHARIOT, ChessPiece.RED, 9, 8));
pieces.add(new ChessPiece(ChessPiece.CANNON, ChessPiece.RED, 7, 1));
pieces.add(new ChessPiece(ChessPiece.CANNON, ChessPiece.RED, 7, 7));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.RED, 6, 0));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.RED, 6, 2));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.RED, 6, 4));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.RED, 6, 6));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.RED, 6, 8));
// 初始化黑方棋子
pieces.add(new ChessPiece(ChessPiece.CHARIOT, ChessPiece.BLACK, 0, 0));
pieces.add(new ChessPiece(ChessPiece.HORSE, ChessPiece.BLACK, 0, 1));
pieces.add(new ChessPiece(ChessPiece.ELEPHANT, ChessPiece.BLACK, 0, 2));
pieces.add(new ChessPiece(ChessPiece.ADVISOR, ChessPiece.BLACK, 0, 3));
pieces.add(new ChessPiece(ChessPiece.GENERAL, ChessPiece.BLACK, 0, 4));
pieces.add(new ChessPiece(ChessPiece.ADVISOR, ChessPiece.BLACK, 0, 5));
pieces.add(new ChessPiece(ChessPiece.ELEPHANT, ChessPiece.BLACK, 0, 6));
pieces.add(new ChessPiece(ChessPiece.HORSE, ChessPiece.BLACK, 0, 7));
pieces.add(new ChessPiece(ChessPiece.CHARIOT, ChessPiece.BLACK, 0, 8));
pieces.add(new ChessPiece(ChessPiece.CANNON, ChessPiece.BLACK, 2, 1));
pieces.add(new ChessPiece(ChessPiece.CANNON, ChessPiece.BLACK, 2, 7));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.BLACK, 3, 0));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.BLACK, 3, 2));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.BLACK, 3, 4));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.BLACK, 3, 6));
pieces.add(new ChessPiece(ChessPiece.SOLDIER, ChessPiece.BLACK, 3, 8));
}
@Override
public void onDraw(Component component, Canvas canvas) {
int width = getWidth();
int height = getHeight();
float cellWidth = width / (float) COLS;
float cellHeight = height / (float) ROWS;
// 绘制棋盘
drawBoard(canvas, width, height, cellWidth, cellHeight);
// 绘制棋子
drawPieces(canvas, cellWidth, cellHeight);
}
private void drawBoard(Canvas canvas, int width, int height, float cellWidth, float cellHeight) {
// 绘制横线
for (int i = 0; i < ROWS; i++) {
float y = i * cellHeight;
canvas.drawLine(0, y, width, y, linePaint);
}
// 绘制竖线
for (int j = 0; j < COLS; j++) {
float x = j * cellWidth;
canvas.drawLine(x, 0, x, height, linePaint);
}
// 绘制楚河汉界
float centerY = (ROWS / 2 - 0.5f) * cellHeight;
canvas.drawText("楚河", width * 0.3f, centerY - 20, textPaint);
canvas.drawText("汉界", width * 0.7f, centerY - 20, textPaint);
// 绘制九宫格
drawNinePalaces(canvas, cellWidth, cellHeight, 0); // 上方九宫格
drawNinePalaces(canvas, cellWidth, cellHeight, 7); // 下方九宫格
}
private void drawNinePalaces(Canvas canvas, float cellWidth, float cellHeight, int startRow) {
float left = 3 * cellWidth;
float top = startRow * cellHeight;
float right = 5 * cellWidth;
float bottom = (startRow + 2) * cellHeight;
// 绘制斜线
canvas.drawLine(left, top, right, bottom, linePaint);
canvas.drawLine(right, top, left, bottom, linePaint);
}
private void drawPieces(Canvas canvas, float cellWidth, float cellHeight) {
for (ChessPiece piece : pieces) {
float centerX = (piece.getCol() + 0.5f) * cellWidth;
float centerY = (piece.getRow() + 0.5f) * cellHeight;
float radius = Math.min(cellWidth, cellHeight) * 0.4f;
// 绘制棋子背景
Paint bgPaint = piece.getColor() == ChessPiece.RED ? redPaint : blackPaint;
canvas.drawCircle(centerX, centerY, radius, bgPaint);
// 绘制棋子文字
textPaint.setColor(piece.getColor() == ChessPiece.RED ? Color.WHITE : Color.WHITE);
canvas.drawText(piece.getName(), centerX, centerY + 15, textPaint);
// 绘制选中状态
if (piece == selectedPiece) {
canvas.drawCircle(centerX, centerY, radius + 5, selectedPaint);
}
}
}
private boolean onTouchEvent(Component component, TouchEvent event) {
if (event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
int width = getWidth();
int height = getHeight();
float cellWidth = width / (float) COLS;
float cellHeight = height / (float) ROWS;
int col = (int) (event.getPointerPosition(0).getX() / cellWidth);
int row = (int) (event.getPointerPosition(0).getY() / cellHeight);
if (row >= 0 && row < ROWS && col >= 0 && col < COLS) {
handleClick(row, col);
}
}
return true;
}
private void handleClick(int row, int col) {
ChessPiece clickedPiece = getPieceAt(row, col);
if (selectedPiece == null) {
// 没有选中棋子时,尝试选中一个棋子
if (clickedPiece != null && clickedPiece.getColor() == currentPlayer) {
selectedPiece = clickedPiece;
invalidate();
}
} else {
// 已经选中了一个棋子
if (clickedPiece != null && clickedPiece.getColor() == currentPlayer) {
// 点击的是己方棋子,切换选中
selectedPiece = clickedPiece;
invalidate();
} else {
// 尝试移动棋子
if (isValidMove(selectedPiece, row, col)) {
// 如果目标位置有对方棋子,则吃掉
if (clickedPiece != null) {
pieces.remove(clickedPiece);
// 检查是否将/帅被吃
if (clickedPiece.getType() == ChessPiece.GENERAL) {
gameOver(currentPlayer);
return;
}
}
// 移动棋子
selectedPiece.setRow(row);
selectedPiece.setCol(col);
// 切换玩家
currentPlayer = (currentPlayer == ChessPiece.RED) ? ChessPiece.BLACK : ChessPiece.RED;
selectedPiece = null;
invalidate();
}
}
}
}
private ChessPiece getPieceAt(int row, int col) {
for (ChessPiece piece : pieces) {
if (piece.getRow() == row && piece.getCol() == col) {
return piece;
}
}
return null;
}
private boolean isValidMove(ChessPiece piece, int toRow, int toCol) {
int fromRow = piece.getRow();
int fromCol = piece.getCol();
// 目标位置不能是己方棋子
ChessPiece targetPiece = getPieceAt(toRow, toCol);
if (targetPiece != null && targetPiece.getColor() == piece.getColor()) {
return false;
}
// 根据棋子类型判断移动是否合法
switch (piece.getType()) {
case ChessPiece.GENERAL: // 将/帅
return isValidGeneralMove(piece, fromRow, fromCol, toRow, toCol);
case ChessPiece.ADVISOR: // 士
return isValidAdvisorMove(piece, fromRow, fromCol, toRow, toCol);
case ChessPiece.ELEPHANT: // 象
return isValidElephantMove(piece, fromRow, fromCol, toRow, toCol);
case ChessPiece.HORSE: // 马
return isValidHorseMove(fromRow, fromCol, toRow, toCol);
case ChessPiece.CHARIOT: // 车
return isValidChariotMove(fromRow, fromCol, toRow, toCol);
case ChessPiece.CANNON: // 炮
return isValidCannonMove(fromRow, fromCol, toRow, toCol);
case ChessPiece.SOLDIER: // 兵/卒
return isValidSoldierMove(piece, fromRow, fromCol, toRow, toCol);
default:
return false;
}
}
private boolean isValidGeneralMove(ChessPiece piece, int fromRow, int fromCol, int toRow, int toCol) {
// 将/帅只能在九宫格内移动
if (piece.getColor() == ChessPiece.RED) {
if (toRow < 7 || toRow > 9 || toCol < 3 || toCol > 5) {
return false;
}
} else {
if (toRow < 0 || toRow > 2 || toCol < 3 || toCol > 5) {
return false;
}
}
// 将/帅每次只能走一格直线
int rowDiff = Math.abs(toRow - fromRow);
int colDiff = Math.abs(toCol - fromCol);
if ((rowDiff == 1 && colDiff == 0) || (rowDiff == 0 && colDiff == 1)) {
return true;
}
// 将帅对面特殊情况
if (fromCol == toCol && colDiff == 0) {
ChessPiece target = getPieceAt(toRow, toCol);
if (target != null && target.getType() == ChessPiece.GENERAL && target.getColor() != piece.getColor()) {
// 检查中间是否有其他棋子
int minRow = Math.min(fromRow, toRow);
int maxRow = Math.max(fromRow, toRow);
for (int r = minRow + 1; r < maxRow; r++) {
if (getPieceAt(r, fromCol) != null) {
return false;
}
}
return true;
}
}
return false;
}
private boolean isValidAdvisorMove(ChessPiece piece, int fromRow, int fromCol, int toRow, int toCol) {
// 士只能在九宫格内移动
if (piece.getColor() == ChessPiece.RED) {
if (toRow < 7 || toRow > 9 || toCol < 3 || toCol > 5) {
return false;
}
} else {
if (toRow < 0 || toRow > 2 || toCol < 3 || toCol > 5) {
return false;
}
}
// 士每次只能走一格斜线
int rowDiff = Math.abs(toRow - fromRow);
int colDiff = Math.abs(toCol - fromCol);
return rowDiff == 1 && colDiff == 1;
}
private boolean isValidElephantMove(ChessPiece piece, int fromRow, int fromCol, int toRow, int toCol) {
// 象不能过河
if (piece.getColor() == ChessPiece.RED && toRow < 5) {
return false;
}
if (piece.getColor() == ChessPiece.BLACK && toRow > 4) {
return false;
}
// 象走田字
int rowDiff = Math.abs(toRow - fromRow);
int colDiff = Math.abs(toCol - fromCol);
if (rowDiff == 2 && colDiff == 2) {
// 检查象眼是否被堵
int eyeRow = (fromRow + toRow) / 2;
int eyeCol = (fromCol + toCol) / 2;
return getPieceAt(eyeRow, eyeCol) == null;
}
return false;
}
private boolean isValidHorseMove(int fromRow, int fromCol, int toRow, int toCol) {
int rowDiff = Math.abs(toRow - fromRow);
int colDiff = Math.abs(toCol - fromCol);
// 马走日
if ((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2)) {
// 检查马腿是否被堵
if (rowDiff == 2) {
int middleRow = (fromRow + toRow) / 2;
return getPieceAt(middleRow, fromCol) == null;
} else {
int middleCol = (fromCol + toCol) / 2;
return getPieceAt(fromRow, middleCol) == null;
}
}
return false;
}
private boolean isValidChariotMove(int fromRow, int fromCol, int toRow, int toCol) {
// 车走直线
if (fromRow != toRow && fromCol != toCol) {
return false;
}
// 检查路径上是否有其他棋子
if (fromRow == toRow) {
int minCol = Math.min(fromCol, toCol);
int maxCol = Math.max(fromCol, toCol);
for (int c = minCol + 1; c < maxCol; c++) {
if (getPieceAt(fromRow, c) != null) {
return false;
}
}
} else {
int minRow = Math.min(fromRow, toRow);
int maxRow = Math.max(fromRow, toRow);
for (int r = minRow + 1; r < maxRow; r++) {
if (getPieceAt(r, fromCol) != null) {
return false;
}
}
}
return true;
}
private boolean isValidCannonMove(int fromRow, int fromCol, int toRow, int toCol) {
// 炮走直线
if (fromRow != toRow && fromCol != toCol) {
return false;
}
ChessPiece targetPiece = getPieceAt(toRow, toCol);
int pieceCount = 0;
// 计算路径上的棋子数量
if (fromRow == toRow) {
int minCol = Math.min(fromCol, toCol);
int maxCol = Math.max(fromCol, toCol);
for (int c = minCol + 1; c < maxCol; c++) {
if (getPieceAt(fromRow, c) != null) {
pieceCount++;
}
}
} else {
int minRow = Math.min(fromRow, toRow);
int maxRow = Math.max(fromRow, toRow);
for (int r = minRow + 1; r < maxRow; r++) {
if (getPieceAt(r, fromCol) != null) {
pieceCount++;
}
}
}
// 炮移动时不能有棋子阻挡
if (targetPiece == null) {
return pieceCount == 0;
}
// 炮吃子时必须有一个棋子作为炮架
else {
return pieceCount == 1;
}
}
private boolean isValidSoldierMove(ChessPiece piece, int fromRow, int fromCol, int toRow, int toCol) {
int rowDiff = toRow - fromRow;
int colDiff = Math.abs(toCol - fromCol);
if (piece.getColor() == ChessPiece.RED) {
// 红方兵向上走
if (rowDiff != -1) {
return false;
}
} else {
// 黑方卒向下走
if (rowDiff != 1) {
return false;
}
}
// 未过河只能向前
if ((piece.getColor() == ChessPiece.RED && fromRow > 4) ||
(piece.getColor() == ChessPiece.BLACK && fromRow < 5)) {
return colDiff == 0;
}
// 过河后可以左右移动
else {
return colDiff == 0 || colDiff == 1;
}
}
private void gameOver(int winner) {
String message = (winner == ChessPiece.RED) ? "红方胜利!" : "黑方胜利!";
if (getContext() instanceof MainAbilitySlice) {
((MainAbilitySlice) getContext()).showGameOverDialog(message);
}
// 重置游戏
initPieces();
currentPlayer = ChessPiece.RED;
selectedPiece = null;
invalidate();
}
public void resetGame() {
initPieces();
currentPlayer = ChessPiece.RED;
selectedPiece = null;
invalidate();
}
}
MainAbilitySlice.java (主界面)
package com.example.chinesechess;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Text;
import ohos.agp.components.Button;
public class MainAbilitySlice extends AbilitySlice {
private ChessView chessView;
private Text statusText;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
DirectionalLayout layout = new DirectionalLayout(this);
layout.setOrientation(DirectionalLayout.VERTICAL);
// 状态文本
statusText = new Text(this);
statusText.setText("当前回合: 红方");
statusText.setTextSize(50);
statusText.setPadding(10, 10, 10, 10);
// 象棋视图
chessView = new ChessView(this);
// 按钮布局
DirectionalLayout buttonLayout = new DirectionalLayout(this);
buttonLayout.setOrientation(DirectionalLayout.HORIZONTAL);
buttonLayout.setPadding(10, 10, 10, 10);
// 重新开始按钮
Button resetButton = new Button(this);
resetButton.setText("重新开始");
resetButton.setClickedListener(component -> {
chessView.resetGame();
statusText.setText("当前回合: 红方");
});
// 悔棋按钮
Button undoButton = new Button(this);
undoButton.setText("悔棋");
undoButton.setClickedListener(component -> {
// 悔棋功能待实现
new ToastDialog(this).setText("悔棋功能待实现").show();
});
buttonLayout.addComponent(resetButton);
buttonLayout.addComponent(undoButton);
layout.addComponent(statusText);
layout.addComponent(chessView);
layout.addComponent(buttonLayout);
super.setUIContent(layout);
}
public void showGameOverDialog(String message) {
new ToastDialog(this)
.setText(message)
.show();
statusText.setText("游戏结束 - " + message);
}
}
ability_main.xml (布局文件)
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:orientation="vertical">
<Text
ohos:id="$+id:status_text"
ohos:width="match_parent"
ohos:height="50vp"
ohos:text="当前回合: 红方"
ohos:text_size="20fp"
ohos:padding="10vp"/>
<com.example.chinesechess.ChessView
ohos:id="$+id:chess_view"
ohos:width="match_parent"
ohos:height="0vp"
ohos:weight="1"/>
<DirectionalLayout
ohos:id="$+id:button_layout"
ohos:width="match_parent"
ohos:height="wrap_content"
ohos:orientation="horizontal"
ohos:padding="10vp">
<Button
ohos:id="$+id:reset_button"
ohos:width="0vp"
ohos:height="50vp"
ohos:weight="1"
ohos:text="重新开始"
ohos:margin="5vp"/>
<Button
ohos:id="$+id:undo_button"
ohos:width="0vp"
ohos:height="50vp"
ohos:weight="1"
ohos:text="悔棋"
ohos:margin="5vp"/>
</DirectionalLayout>
</DirectionalLayout>
3. 功能说明
- 游戏规则:标准中国象棋规则
- 棋子类型:
- 界面元素:
- 棋盘:9×10网格,包含楚河汉界和九宫格
- 棋子:红黑两色,带有汉字标识
- 状态显示:当前回合信息
- 操作按钮:重新开始、悔棋(待实现)
- 交互:
- 点击选中棋子
- 再次点击目标位置移动棋子
- 自动判断移动是否合法
- 自动判断胜负