美文网首页
鸿蒙开发案例:绘制中国象棋棋盘与棋子的技术教程

鸿蒙开发案例:绘制中国象棋棋盘与棋子的技术教程

作者: zhongcx | 来源:发表于2024-10-29 03:59 被阅读0次
a41.gif

本文将介绍如何使用鸿蒙提供的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%');
  }
}

相关文章

  • 五子棋程序UML类图解释

    棋盘类继承于窗口类,实现了窗口类的函数。定义棋盘类绘制棋盘,与棋盘类为组合关系。使用棋子绘制棋盘属于依赖关系。棋子...

  • 中国象棋游戏基本规则

    中国象棋游戏基本规则 一、棋盘与棋子 1、棋盘:红黑双方分别掌控楚河汉界各一方。 2、棋子:32颗,各16颗。 ...

  • 小程序Canvas闪屏处理

    背景 最近在微信小程序开发中需要用到canvas绘制中国象棋的的棋盘棋子,该需求用来复盘对弈记录,由于复盘的每一步...

  • Android象棋游戏开发之--游戏规则

    源码下载 棋盘棋子绘制完成后,接下来玩家要移动棋子开始与机器对弈。那么如何判断当前棋子移动合法? 棋盘中所有的位置...

  • 百货50条,全部是实用的玩意儿(09.17)

    【中国象棋套装 35#桉木 含塑料棋盘 棋子直径3.3cm 6.9元】 款象棋采用桉木材质,实木防开裂,棋子直径2...

  • ios 绘图 UIBezierPath 中国象棋棋盘

    ios 绘图 UIBezierPath 中国象棋棋盘 先看看效果 开发思路 中国象棋基本格式 纵坐标 9 横坐标 ...

  • 认识围棋|围棋入门01

    一、棋盘与棋子 围棋的棋具,主要由棋盘、棋子构成。 棋盘是方形的,棋子是圆形的。古人认为方圆象征天地,天圆而动,地...

  • 棋盘与棋子

    棋盘中间的界河,也可以称之为“河界”。河界将棋盘划分成两个阵地,棋局开始时红、黑棋子各据一方。每方阵地中央靠着各自...

  • Android象棋游戏开发之--绘制棋盘

    源码下载 棋盘效果图:红方为玩家黑方为机器 棋盘由四层叠加绘制而成:最底层:整体背景图倒二层:棋盘图倒三层:棋子背...

  • 【Canvas】使用Vue3+TS+Canvas实现五子棋

    1.效果预览 2.实现思路 创建画布 创建绘制对象和棋盘DOM 使用二维数组记录棋盘格的信息 记录当前要下的棋子是...

网友评论

      本文标题:鸿蒙开发案例:绘制中国象棋棋盘与棋子的技术教程

      本文链接:https://www.haomeiwen.com/subject/istmdjtx.html