本文将介绍如何使用鸿蒙提供的UI组件来绘制一个中国象棋棋盘并放置棋子。通过本教程,您将学会基本的UI构建技巧,以及如何在鸿蒙环境中创建一个简单的象棋游戏界面。
一、定义棋盘线条与棋子位置
首先,我们需要定义几个基础类来帮助我们构造棋盘。ChessLine类用于表示棋盘上的线段,而MyPosition类则用来记录棋盘上每个位置是否需要特殊的标记(如“兵”、“卒”、“炮”的位置)。
class ChessLine {
startPoint: [number, number] = [0, 0];
endPoint: [number, number] = [0, 0];
}
class MyPosition {
x: number = 0;
y: number = 0;
topLeft: boolean = true;
topRight: boolean = true;
bottomLeft: boolean = true;
bottomRight: boolean = true;
constructor(x: number, y: number, topLeft: boolean, topRight: boolean, bottomLeft: boolean, bottomRight: boolean) {
this.x = x;
this.y = y;
this.topLeft = topLeft;
this.topRight = topRight;
this.bottomLeft = bottomLeft;
this.bottomRight = bottomRight;
}
}
二、创建棋子类
接下来,我们定义ChessPiece类来代表棋盘上的每一个棋子。这个类包括棋子的颜色、类型等属性,并且有一个方法getColor()来获取棋子的颜色值。
@ObservedV2
class ChessPiece {
@Trace opacity: number = 1;
@Trace value: string = "";
@Trace type: number = 0; // 0: 无棋, 1: 红棋,2: 黑棋
redColor: string = `rgb(144,11,11)`;
blackColor: string = `rgb(78,56,23)`;
constructor(value: string, type: number) {
this.value = value;
this.type = type;
}
setValue(value: string, type: number) {
this.value = value;
this.type = type;
}
getColor() {
if (this.type === 1) {
return this.redColor;
} else if (this.type === 2) {
return this.blackColor;
}
return "#00000000";
}
}
三、构建棋盘
使用ChessBoard类来构建整个棋盘,其中包括棋盘的基本尺寸、棋子数组、棋盘线段数组等。在这个类中,我们还定义了初始化游戏的方法initGame(),它会根据规则在棋盘上放置棋子。
@Entry
@Component
struct ChessBoard {
cellWidth: number = 70;
borderPieceWidth: number = 12;
pieceSize: number = 66;
pieces: ChessPiece[] = [];
lines: ChessLine[] = [];
positions: MyPosition[] = [];
selectedIndex: number = -1; // -1表示未点击任何棋子,非-1表示当前正在点击的棋子
aboutToAppear(): void {
for (let i = 0; i < 9 * 10; i++) {
this.pieces.push(new ChessPiece("", 0));
}
this.initGame();
// 初始化水平线和垂直线...
}
initGame() {
// 设置棋子初始位置...
}
build() {
Column({ space: 10 }) {
// 构建棋盘框架和线条...
}
}
}
四、绘制棋子
最后,我们需要在棋盘上绘制棋子。这里使用了Flex和ForEach等组件来遍历棋子数组,并根据棋子的类型绘制不同的样式。
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.pieces, (piece: ChessPiece, index: number) => {
Stack() {
Text(piece.value)
// 设置棋子文本样式...
}
.opacity(piece.opacity)
.width(`${this.cellWidth}lpx`)
.height(`${this.cellWidth}lpx`)
.onClick(() => {
// 处理点击事件...
})
})
}
【完整代码】
class ChessLine {
startPoint: [number, number] = [0, 0];
endPoint: [number, number] = [0, 0];
}
class MyPosition {
x: number = 0;
y: number = 0;
topLeft: boolean = true;
topRight: boolean = true;
bottomLeft: boolean = true;
bottomRight: boolean = true;
constructor(x: number, y: number, topLeft: boolean, topRight: boolean, bottomLeft: boolean, bottomRight: boolean) {
this.x = x;
this.y = y;
this.topLeft = topLeft;
this.topRight = topRight;
this.bottomLeft = bottomLeft;
this.bottomRight = bottomRight;
}
}
@ObservedV2
class ChessPiece {
@Trace opacity: number = 1;
@Trace value: string = "";
@Trace type: number = 0; // 0: 无棋, 1: 红棋,2: 黑棋
redColor: string = `rgb(144,11,11)`;
blackColor: string = `rgb(78,56,23)`;
constructor(value: string, type: number) {
this.value = value;
this.type = type;
}
setValue(value: string, type: number) {
this.value = value;
this.type = type;
}
getColor() {
if (this.type === 1) {
return this.redColor;
} else if (this.type === 2) {
return this.blackColor;
}
return "#00000000";
}
}
@Entry
@Component
struct ChessBoard {
cellWidth: number = 70;
borderPieceWidth: number = 12;
pieceSize: number = 66;
pieces: ChessPiece[] = [];
lines: ChessLine[] = [];
positions: MyPosition[] = [];
selectedIndex: number = -1; // -1表示未点击任何棋子,非-1表示当前正在点击的棋子
aboutToAppear(): void {
for (let i = 0; i < 9 * 10; i++) {
this.pieces.push(new ChessPiece("", 0));
}
this.initGame();
// 初始化水平线和垂直线
for (let i = 0; i < 10; i++) {
this.lines.push({
startPoint: [0, this.cellWidth * i],
endPoint: [this.cellWidth * 8, this.cellWidth * i]
});
this.lines.push({
startPoint: [this.cellWidth * i, 0],
endPoint: [this.cellWidth * i, this.cellWidth * (i === 0 || i === 8 ? 9 : 4)]
});
this.lines.push({
startPoint: [this.cellWidth * i, this.cellWidth * 5],
endPoint: [this.cellWidth * i, this.cellWidth * 9]
});
}
// 初始化九宫格内的斜线
this.lines.push({
startPoint: [3 * this.cellWidth, 0],
endPoint: [5 * this.cellWidth, 2 * this.cellWidth],
});
this.lines.push({
startPoint: [5 * this.cellWidth, 0],
endPoint: [3 * this.cellWidth, 2 * this.cellWidth],
});
this.lines.push({
startPoint: [3 * this.cellWidth, 7 * this.cellWidth],
endPoint: [5 * this.cellWidth, 9 * this.cellWidth],
});
this.lines.push({
startPoint: [5 * this.cellWidth, 7 * this.cellWidth],
endPoint: [3 * this.cellWidth, 9 * this.cellWidth],
});
// 兵卒炮位置标
this.positions.push(new MyPosition(1, 2, true, true, true, true))
this.positions.push(new MyPosition(7, 2, true, true, true, true))
this.positions.push(new MyPosition(0, 3, false, true, false, true))
this.positions.push(new MyPosition(2, 3, true, true, true, true))
this.positions.push(new MyPosition(4, 3, true, true, true, true))
this.positions.push(new MyPosition(6, 3, true, true, true, true))
this.positions.push(new MyPosition(8, 3, true, false, true, false))
this.positions.push(new MyPosition(1, 7, true, true, true, true))
this.positions.push(new MyPosition(7, 7, true, true, true, true))
this.positions.push(new MyPosition(0, 6, false, true, false, true))
this.positions.push(new MyPosition(2, 6, true, true, true, true))
this.positions.push(new MyPosition(4, 6, true, true, true, true))
this.positions.push(new MyPosition(6, 6, true, true, true, true))
this.positions.push(new MyPosition(8, 6, true, false, true, false))
}
initGame() {
for (let i = 0; i < 9 * 10; i++) {
this.pieces[i].setValue("", 0);
}
this.pieces[0].setValue("车", 2)
this.pieces[1].setValue("马", 2)
this.pieces[2].setValue("象", 2)
this.pieces[3].setValue("士", 2)
this.pieces[4].setValue("将", 2)
this.pieces[5].setValue("士", 2)
this.pieces[6].setValue("象", 2)
this.pieces[7].setValue("马", 2)
this.pieces[8].setValue("车", 2)
this.pieces[19].setValue("炮", 2)
this.pieces[25].setValue("炮", 2)
this.pieces[27].setValue("卒", 2)
this.pieces[29].setValue("卒", 2)
this.pieces[31].setValue("卒", 2)
this.pieces[33].setValue("卒", 2)
this.pieces[35].setValue("卒", 2)
this.pieces[54].setValue("兵", 1)
this.pieces[56].setValue("兵", 1)
this.pieces[58].setValue("兵", 1)
this.pieces[60].setValue("兵", 1)
this.pieces[62].setValue("兵", 1)
this.pieces[64].setValue("炮", 1)
this.pieces[70].setValue("炮", 1)
this.pieces[81].setValue("车", 1)
this.pieces[82].setValue("马", 1)
this.pieces[83].setValue("相", 1)
this.pieces[84].setValue("仕", 1)
this.pieces[85].setValue("帅", 1)
this.pieces[86].setValue("仕", 1)
this.pieces[87].setValue("相", 1)
this.pieces[88].setValue("马", 1)
this.pieces[89].setValue("车", 1)
}
build() {
Column({ space: 10 }) {
Column() {
Stack() {
// 棋盘矩形边框
Rect()
.margin({
top: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`,
left: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`
})
.width(`${this.cellWidth * 8 + this.borderPieceWidth}lpx`)
.height(`${this.cellWidth * 9 + this.borderPieceWidth}lpx`)
.fillOpacity(0)
.stroke(Color.Black)
.strokeWidth(`${this.borderPieceWidth / 3}lpx`);
// 绘制线条
ForEach(this.lines, (line: ChessLine, _index: number) => {
Line()
.margin({ left: `${this.cellWidth / 2}lpx`, top: `${this.cellWidth / 2}lpx` })
.startPoint([`${line.startPoint[0]}lpx`, `${line.startPoint[1]}lpx`])
.endPoint([`${line.endPoint[0]}lpx`, `${line.endPoint[1]}lpx`])
.stroke(Color.Black);
});
// 添加"兵卒炮"标记
ForEach(this.positions, (position: MyPosition, _index: number) => {
if (position.topLeft) {
Polyline()
.margin({
left: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`,
top: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`
})
.points([
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y - this.borderPieceWidth}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x - this.borderPieceWidth}lpx`, `${this.cellWidth * position.y}lpx`],
])
.width(1)
.height(1)
.fillOpacity(0)
.stroke(Color.Black);
}
if (position.topRight) {
Polyline()
.margin({
left: `${this.cellWidth / 2 + this.borderPieceWidth / 2}lpx`,
top: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`
})
.points([
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y - this.borderPieceWidth}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x + this.borderPieceWidth}lpx`, `${this.cellWidth * position.y}lpx`],
])
.width(1)
.height(1)
.fillOpacity(0)
.stroke(Color.Black)
}
if (position.bottomLeft) {
Polyline()
.margin({
left: `${this.cellWidth / 2 - this.borderPieceWidth / 2}lpx`,
top: `${this.cellWidth / 2 + this.borderPieceWidth / 2}lpx`
})
.points([
[`${this.cellWidth * position.x - this.borderPieceWidth}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y + this.borderPieceWidth}lpx`],
])
.width(1)
.height(1)
.fillOpacity(0)
.stroke(Color.Black)
}
if (position.bottomRight) {
Polyline()
.margin({
left: `${this.cellWidth / 2 + this.borderPieceWidth / 2}lpx`,
top: `${this.cellWidth / 2 + this.borderPieceWidth / 2}lpx`
})
.points([
[`${this.cellWidth * position.x + this.borderPieceWidth}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y}lpx`],
[`${this.cellWidth * position.x}lpx`, `${this.cellWidth * position.y + this.borderPieceWidth}lpx`],
])
.width(1)
.height(1)
.fillOpacity(0)
.stroke(Color.Black)
}
});
// 绘制棋子
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.pieces, (piece: ChessPiece, index: number) => {
Stack() {
Text(piece.value)
.width(`${this.pieceSize}lpx`)
.height(`${this.pieceSize}lpx`)
.backgroundColor(piece.type !== 0 ? `rgb(192,149,106)` : Color.Transparent)
.textAlign(TextAlign.Center)
.fontSize(`${this.pieceSize / 2}lpx`)
.fontColor(piece.getColor())
.borderColor(piece.getColor())
.borderRadius(`50%`)
.borderWidth(`2lpx`)
.textShadow({
radius: 2,
color: Color.White,
offsetX: 2,
offsetY: 2
});
Circle()
.width(`${this.pieceSize - 15}lpx`)
.height(`${this.pieceSize - 15}lpx`)
.fillOpacity(0)
.strokeWidth(2)
.stroke(piece.getColor())
.strokeDashArray([0.2, 1]);
}
.opacity(piece.opacity)
.width(`${this.cellWidth}lpx`)
.height(`${this.cellWidth}lpx`)
.onClick(() => {
if (this.selectedIndex === -1) {
this.selectedIndex = index;
animateToImmediately({
iterations: 3,
duration: 300,
onFinish: () => {
animateToImmediately({
iterations: 1,
duration: 0
}, () => {
piece.opacity = 1;
});
}
}, () => {
piece.opacity = 0.5;
});
} else {
piece.value = this.pieces[this.selectedIndex].value;
piece.type = this.pieces[this.selectedIndex].type;
this.pieces[this.selectedIndex].value = '';
this.pieces[this.selectedIndex].type = 0;
this.selectedIndex = -1;
}
});
});
}.width('100%').height('100%');
}
.align(Alignment.TopStart)
.width(`${this.cellWidth * 9}lpx`)
.height(`${this.cellWidth * 10}lpx`);
}
.padding(10)
.backgroundColor(Color.Orange)
.borderRadius(10);
Button('重新开始').onClick(() => {
this.initGame();
});
}.width('100%');
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。