鸿蒙开发案例:黑白棋

 

黑白棋,又叫翻转棋(Reversi)、奥赛罗棋(Othello)、苹果棋或正反棋(Anti reversi)。黑白棋在西方和日本很流行。游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。它的游戏规则简单,因此上手很容易,但是它的变化又非常复杂。有一种说法是:只需要几分钟学会它,却需要一生的时间去精通它。

此代码基于API 12编写,包含了游戏的基本逻辑,包括初始化棋盘、处理玩家和AI的走法、检查游戏状态、以及动画展示等部分。以下是具体的功能和使用的算法分析:

【实现的功能】

1. 棋盘初始化:创建了一个8×8的棋盘,并在中心位置放置了四个棋子作为初始布局,遵循了翻转棋的标准规则。

2. 棋子展示与翻转:定义了ChessCell类来表示棋盘上的每个单元格,支持显示黑色或白色棋子,并且能够翻转棋子,即从黑色变为白色或反之亦然。此过程伴随有动画效果。

3. 有效走法检测:通过findReversible方法来查找某个位置放置新棋子后可翻转的棋子集合。此方法考虑了八个方向上的可能走法。

4. 玩家切换:currentPlayerIsBlackChanged方法用于切换当前玩家,并检查当前玩家是否有有效的走法。如果没有,就检查对手是否有走法,如果没有则判定游戏结束并显示胜利者。

5. AI走法:在单人模式下,AI会选择一个随机的有效走法进行下棋。6. 游戏结束判定:当没有任何一方可以走棋时,游戏结束并显示胜利信息。

【使用的算法】

1. 有效走法检测算法

有效走法检测是通过findReversible函数实现的。该函数接收行号、列号和当前玩家的颜色作为参数,并返回一个数组,该数组包含所有可以在指定方向上翻转的棋子对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
findReversible(row: number, col: number, color: number): ChessCell[] {
    let reversibleTiles: ChessCell[] = [];
    const directions = [
        [-1, -1], // 左上
        [-1, 0], // 正上
        [-1, 1], // 右上
        [0, -1], // 左
        [0, 1], // 右
        [1, -1], // 左下
        [1, 0], // 正下
        [1, 1]  // 右下
    ];
    for (const direction of directions) {
        let foundOpposite = false;
        let x = row;
        let y = col;
        do {
            x += direction[0];
            y += direction[1];
            if (x < 0 || y < 0 || x >= this.chessBoardSize || y >= this.chessBoardSize) {
                break;
            }
            const cell = this.chessBoard[x][y];
            if (cell.frontVisibility === 0) {
                break;
            }
            if (cell.frontVisibility === color) {
                if (foundOpposite) {
                    let tempX: number = x - direction[0];
                    let tempY: number = y - direction[1];
                    while (tempX !== row || tempY !== col) {
                        reversibleTiles.push(this.chessBoard[tempX][tempY]);
                        tempX -= direction[0];
                        tempY -= direction[1];
                    }
                }
                break;
            } else {
                foundOpposite = true;
            }
        } while (true);
    }
    return reversibleTiles;
}

  

该算法首先定义了所有可能的方向,然后逐一检查这些方向上是否存在有效的可翻转棋子序列。对于每一个方向,它会尝试移动到下一个位置,并检查那个位置上的棋子状态,如果遇到空位则停止搜索;如果遇到同色棋子,那么在这之前的所有异色棋子都可以被翻转;否则继续搜索直到边界或同色棋子出现。

2. AI随机下棋策略

AI的随机下棋策略是在aiPlaceRandom函数中实现的。该函数首先收集所有当前玩家可以下棋的位置,然后从中随机选择一个位置进行下棋。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
aiPlaceRandom() {
    let validMoves: [number, number][] = [];
    for (let i = 0; i < this.validMoveIndicators.length; i++) {
        for (let j = 0; j < this.validMoveIndicators[i].length; j++) {
            if (this.validMoveIndicators[i][j].isValidMove) {
                validMoves.push([i, j]);
            }
        }
    }
    if (validMoves.length > 0) {
        const randomMove = validMoves[Math.floor(Math.random() * validMoves.length)];
        let chessCell = this.chessBoard[randomMove[0]][randomMove[1]];
        this.placeChessPiece(randomMove[0], randomMove[1], chessCell)
    }
}

  

这里通过双重循环遍历所有的validMoveIndicators数组,找到所有标记为有效走法的位置,将其坐标存储在一个数组中。之后,从中随机选取一个坐标,调用placeChessPiece函数进行下棋。

3. 棋子翻转动画

棋子的翻转动画是由ChessCell类中的flip方法控制的。根据当前棋子的状态,调用相应颜色的展示方法(如showBlack或showWhite),并根据传入的时间参数来决定是否启用动画。

1
2
3
4
5
6
7
flip(time: number) {
    if (this.frontVisibility === 1) { // 当前是黑子,要翻转成白子
        this.showWhite(time);
    } else if (this.frontVisibility === 2) { // 当前是白子,要翻转成黑子
        this.showBlack(time);
    }
}

  

翻转操作会触发动画效果,通过旋转和透明度的变化来模拟棋子的翻转动作。这些算法共同作用,使得该游戏具有了基础的棋子翻转、有效走法检测和AI下棋的能力。

【完整代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
import { promptAction } from '@kit.ArkUI'; // 导入用于弹出对话框的工具
 
@ObservedV2
class ChessCell { // 定义棋盘上的单元格类
  @Trace frontVisibility: number = 0; // 单元格上的棋子状态:0表示无子, 1表示黑子,2表示白子
  @Trace rotationAngle: number = 0; // 单元格卡片的旋转角度
  @Trace opacity: number = 1; // 透明度
  isAnimationRunning: boolean = false; // 标记动画是否正在运行
 
  flip(time: number) { // 翻转棋子的方法
    if (this.frontVisibility === 1) { // 当前是黑子,要翻转成白子
      this.showWhite(time);
    } else if (this.frontVisibility === 2) { // 当前是白子,要翻转成黑子
      this.showBlack(time);
    }
  }
 
  showBlack(animationTime: number, callback?: () => void) { // 展示黑色棋子
    if (this.isAnimationRunning) { // 如果已经有动画在运行,则返回
      return;
    }
    this.isAnimationRunning = true; // 设置动画状态为运行中
    if (animationTime == 0) { // 如果不需要动画
      this.rotationAngle = 0; // 设置旋转角度为0
      this.frontVisibility = 1; // 黑子
      this.isAnimationRunning = false; // 设置动画状态为停止
      if (callback) { // 如果有回调函数,则执行
        callback();
      }
    }
 
    animateToImmediately({
      // 开始动画
      duration: animationTime, // 动画持续时间
      iterations: 1, // 动画迭代次数
      curve: Curve.Linear, // 动画曲线类型
      onFinish: () => { // 动画完成后的回调
        animateToImmediately({
          // 再次开始动画
          duration: animationTime, // 动画持续时间
          iterations: 1, // 动画迭代次数
          curve: Curve.Linear, // 动画曲线类型
          onFinish: () => { // 动画完成后的回调
            this.isAnimationRunning = false; // 设置动画状态为停止
            if (callback) { // 如果有回调函数,则执行
              callback();
            }
          }
        }, () => { // 动画开始时的回调
          this.frontVisibility = 1; // 看到黑色
          this.rotationAngle = 0; // 设置旋转角度为0
        });
      }
    }, () => { // 动画开始时的回调
      this.rotationAngle = 90; // 设置旋转角度为90度
    });
  }
 
  showWhite(animationTime: number, callback?: () => void) { // 展示白色棋子
    if (this.isAnimationRunning) { // 如果已经有动画在运行,则返回
      return;
    }
    this.isAnimationRunning = true; // 设置动画状态为运行中
    if (animationTime == 0) { // 如果不需要动画
      this.rotationAngle = 180; // 设置旋转角度为180度
      this.frontVisibility = 2; // 白子
      this.isAnimationRunning = false; // 设置动画状态为停止
      if (callback) { // 如果有回调函数,则执行
        callback();
      }
    }
 
    animateToImmediately({
      // 开始动画
      duration: animationTime, // 动画持续时间
      iterations: 1, // 动画迭代次数
      curve: Curve.Linear, // 动画曲线类型
      onFinish: () => { // 动画完成后的回调
        animateToImmediately({
          // 再次开始动画
          duration: animationTime, // 动画持续时间
          iterations: 1, // 动画迭代次数
          curve: Curve.Linear, // 动画曲线类型
          onFinish: () => { // 动画完成后的回调
 
            this.isAnimationRunning = false; // 设置动画状态为停止
            if (callback) { // 如果有回调函数,则执行
              callback();
            }
          }
        }, () => { // 动画开始时的回调
          this.frontVisibility = 2; // 看到白色
          this.rotationAngle = 180; // 设置旋转角度为180度
        });
      }
    }, () => { // 动画开始时的回调
      this.rotationAngle = 90; // 设置旋转角度为90度
    });
  }
 
  showWhiteAi(animationTime: number, callback?: () => void) { // 展示白色棋子
    if (this.isAnimationRunning) { // 如果已经有动画在运行,则返回
      return;
    }
    this.isAnimationRunning = true; // 设置动画状态为运行中
    if (animationTime == 0) { // 如果不需要动画
      this.rotationAngle = 180; // 设置旋转角度为180度
      this.frontVisibility = 2; // 白子
      this.isAnimationRunning = false; // 设置动画状态为停止
      if (callback) { // 如果有回调函数,则执行
        callback();
      }
    }
    this.rotationAngle = 180; // 设置旋转角度为180度
    this.frontVisibility = 2; // 白子
 
 
    animateToImmediately({
      // 开始动画
      duration: animationTime * 3, // 动画持续时间
      curve: Curve.EaseOut,
      iterations: 3, // 动画迭代次数
      onFinish: () => { // 动画完成后的回调
        animateToImmediately({
          // 再次开始动画
          duration: animationTime, // 动画持续时间
          iterations: 1, // 动画迭代次数
          curve: Curve.Linear, // 动画曲线类型
          onFinish: () => { // 动画完成后的回调
 
            this.isAnimationRunning = false; // 设置动画状态为停止
            if (callback) { // 如果有回调函数,则执行
              callback();
            }
          }
        }, () => {
          this.opacity = 1;
        });
      }
    }, () => {
      this.opacity = 0.2;
    });
  }
}
 
@ObservedV2
class TileHighlight {
  @Trace isValidMove: boolean = false;
}
 
@Entry
@Component
struct OthelloGame {
  @State chessBoard: ChessCell[][] = [];
  @State cellSize: number = 70;
  @State cellSpacing: number = 5;
  @State transitionDuration: number = 200;
  @State @Watch('currentPlayerIsBlackChanged') currentPlayerIsBlack: boolean = true; // 先手,true表示黑棋
  @State chessBoardSize: number = 8; // 假设棋盘大小为8×8
  @State validMoveIndicators: TileHighlight [][] = []
  @State isTwoPlayerMode: boolean = false; //true:双击游戏,false:单人游戏
  @State isAIPlaying:boolean = false//true:AI正在下棋
  currentPlayerIsBlackChanged() {
    setTimeout(() => {
      const color = this.currentPlayerIsBlack ? 1 : 2; // 1是黑子,2表示白子
      let hasMoves = this.hasValidMoves(color);
 
      if (!hasMoves) {
        let opponentHasMoves = this.hasValidMoves(!this.currentPlayerIsBlack ? 1 : 2);
        if (!opponentHasMoves) {
          const winner = this.determineWinner();
          console.log(winner);
          promptAction.showDialog({
            title: '游戏结束',
            message: `${winner}`,
            buttons: [{ text: '重新开始', color: '#ffa500' }]
          }).then(() => {
            this.initGame();
          });
        } else {
          this.currentPlayerIsBlack = !this.currentPlayerIsBlack; // 切换下一玩家
        }
      } else {
        if (!this.currentPlayerIsBlack) { // 当前是白棋, 模拟AI下棋
          if (!this.isTwoPlayerMode) {
            setTimeout(() => {
              this.aiPlaceRandom();
            }, this.transitionDuration + 20);
          }
        }
      }
    }, this.transitionDuration + 20);
  }
 
  aiPlaceRandom() {
    let validMoves: [number, number][] = [];
    for (let i = 0; i < this.validMoveIndicators.length; i++) {
      for (let j = 0; j < this.validMoveIndicators[i].length; j++) {
        if (this.validMoveIndicators[i][j].isValidMove) {
          validMoves.push([i, j]);
        }
      }
    }
 
    if (validMoves.length > 0) {
      const randomMove = validMoves[Math.floor(Math.random() * validMoves.length)];
      let chessCell = this.chessBoard[randomMove[0]][randomMove[1]];
      this.placeChessPiece(randomMove[0], randomMove[1], chessCell)
    }
  }
 
  placeChessPiece(i: number, j: number, chessCell: ChessCell) {
 
 
    let reversibleTiles = this.findReversible(i, j, this.currentPlayerIsBlack ? 1 : 2);
    console.info(`reversibleTiles:${JSON.stringify(reversibleTiles)}`);
 
    if (reversibleTiles.length > 0) {
      if (this.currentPlayerIsBlack) {
        this.currentPlayerIsBlack = false;
        chessCell.showBlack(0);
        for (let i = 0; i < reversibleTiles.length; i++) {
          reversibleTiles[i].flip(this.transitionDuration);
        }
      } else {
        this.currentPlayerIsBlack = true;
        if (this.isTwoPlayerMode) { //双人游戏,无动画
          chessCell.showWhite(0);
          for (let i = 0; i < reversibleTiles.length; i++) {
            reversibleTiles[i].flip(this.transitionDuration);
          }
 
        } else { //单人游戏,落子需要闪烁动画
          this.isAIPlaying = true//AI 正在下棋
          chessCell.showWhiteAi(this.transitionDuration, () => {
            for (let i = 0; i < reversibleTiles.length; i++) {
              reversibleTiles[i].flip(this.transitionDuration);
            }
            this.currentPlayerIsBlackChanged()
            this.isAIPlaying = false//AI下完了
          });
        }
      }
    }
  }
 
  hasValidMoves(color: number) {
    let hasMoves = false;
    for (let row = 0; row < this.chessBoardSize; row++) {
      for (let col = 0; col < this.chessBoardSize; col++) {
        if (this.chessBoard[row][col].frontVisibility === 0 && this.findReversible(row, col, color).length > 0) {
          this.validMoveIndicators[row][col].isValidMove = true;
          hasMoves = true;
        } else {
          this.validMoveIndicators[row][col].isValidMove = false;
        }
      }
    }
    return hasMoves;
  }
 
  aboutToAppear(): void {
    for (let i = 0; i < this.chessBoardSize; i++) {
      this.chessBoard.push([]);
      this.validMoveIndicators.push([])
      for (let j = 0; j < this.chessBoardSize; j++) {
        this.chessBoard[i].push(new ChessCell());
        this.validMoveIndicators[i].push(new TileHighlight())
      }
    }
 
    this.initGame()
  }
 
  initGame() {
    this.currentPlayerIsBlack = true
    for (let i = 0; i < this.chessBoardSize; i++) {
      for (let j = 0; j < this.chessBoardSize; j++) {
        this.chessBoard[i][j].frontVisibility = 0
      }
    }
    // 初始棋盘布局
    this.chessBoard[3][3].frontVisibility = 2;
    this.chessBoard[3][4].frontVisibility = 1;
    this.chessBoard[4][3].frontVisibility = 1;
    this.chessBoard[4][4].frontVisibility = 2;
 
    this.currentPlayerIsBlackChanged();
  }
 
  findReversible(row: number, col: number, color: number): ChessCell[] {
    let reversibleTiles: ChessCell[] = [];
    const directions = [
      [-1, -1], // 左上
      [-1, 0], // 正上
      [-1, 1], // 右上
      [0, -1], // 左
      [0, 1], // 右
      [1, -1], // 左下
      [1, 0], // 正下
      [1, 1]// 右下
    ];
    for (const direction of directions) {
      let foundOpposite = false;
      let x = row;
      let y = col;
      do {
        x += direction[0];
        y += direction[1];
        if (x < 0 || y < 0 || x >= this.chessBoardSize || y >= this.chessBoardSize) {
          break;
        }
        const cell = this.chessBoard[x][y];
        if (cell.frontVisibility === 0) {
          break;
        }
        if (cell.frontVisibility === color) {
          if (foundOpposite) {
            let tempX: number = x - direction[0];
            let tempY: number = y - direction[1];
            while (tempX !== row || tempY !== col) {
              reversibleTiles.push(this.chessBoard[tempX][tempY]);
              tempX -= direction[0];
              tempY -= direction[1];
            }
          }
          break;
        } else {
          foundOpposite = true;
        }
      } while (true);
    }
    return reversibleTiles;
  }
 
  determineWinner(): string {
    let blackCount = 0;
    let whiteCount = 0;
    for (let row of this.chessBoard) {
      for (let cell of row) {
        if (cell.frontVisibility === 1) {
          blackCount++;
        }
        if (cell.frontVisibility === 2) {
          whiteCount++;
        }
      }
    }
    if (blackCount > whiteCount) {
      return "黑棋获胜!";
    }
    if (whiteCount > blackCount) {
      return "白棋获胜!";
    }
    return "平局!";
  }
 
  hasValidMove(color: number): boolean {
    for (let row = 0; row < this.chessBoardSize; row++) {
      for (let col = 0; col < this.chessBoardSize; col++) {
        if (this.chessBoard[row][col].frontVisibility === 0 && this.findReversible(row, col, color).length > 0) {
          return true;
        }
      }
    }
    return false;
  }
 
  build() {
    Column({ space: 20 }) {
      Row() {
        Row() {
          Text(``)// 显示单元格的值或空字符串
            .width(`${this.cellSize}lpx`)// 设置宽度
            .height(`${this.cellSize}lpx`)// 设置高度
            .textAlign(TextAlign.Center)// 文本居中
            .backgroundColor(Color.Black)// 设置背景颜色
            .borderRadius('50%')// 设置圆角
            .padding(10)
          Text(`黑棋行动`)
            .fontColor(Color.White)
            .padding(10)
        }
        .visibility(this.currentPlayerIsBlack ? Visibility.Visible : Visibility.Hidden)
 
 
        Row() {
          Text(`白棋行动`)
            .fontColor(Color.White)
            .padding(10)
          Text()// 显示单元格的值或空字符串
            .width(`${this.cellSize}lpx`)// 设置宽度
            .height(`${this.cellSize}lpx`)// 设置高度
            .textAlign(TextAlign.Center)// 文本居中
            .backgroundColor(Color.White)// 设置背景颜色
            .fontColor(Color.White)
            .borderRadius('50%')// 设置圆角
            .padding(10)
        }
        .visibility(!this.currentPlayerIsBlack ? Visibility.Visible : Visibility.Hidden)
      }
      .width(`${(this.cellSize + this.cellSpacing * 2) * 8}lpx`) // 设置宽度
      .justifyContent(FlexAlign.SpaceBetween)
      .margin({ top: 20 })
 
      Stack() {
        //棋盘背景
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.validMoveIndicators, (row: boolean[], _rowIndex: number) => {
            ForEach(row, (item: TileHighlight, _colIndex: number) => {
              Text(`${item.isValidMove ? '+' : ''}`)// 显示单元格的值或空字符串
                .width(`${this.cellSize}lpx`)// 设置宽度
                .height(`${this.cellSize}lpx`)// 设置高度
                .margin(`${this.cellSpacing}lpx`)
                .fontSize(`${this.cellSize / 2}lpx`)// 设置字体大小
                .fontColor(Color.White)
                .textAlign(TextAlign.Center)// 文本居中
                .backgroundColor(Color.Gray)// 设置背景颜色
                .borderRadius(2) // 设置圆角
            });
          });
        }
        .width(`${(this.cellSize + this.cellSpacing * 2) * 8}lpx`) // 设置宽度
        //棋子
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.chessBoard, (row: ChessCell[], rowIndex: number) => {
            ForEach(row, (chessCell: ChessCell, colIndex: number) => {
              Text(``)// 显示单元格的值或空字符串
                .width(`${this.cellSize}lpx`)// 设置宽度
                .height(`${this.cellSize}lpx`)// 设置高度
                .margin(`${this.cellSpacing}lpx`)// 设置边距
                .fontSize(`${this.cellSize / 2}lpx`)// 设置字体大小
                .textAlign(TextAlign.Center)// 文本居中
                .opacity(chessCell.opacity)
                .backgroundColor(chessCell.frontVisibility != 0 ?
                  (chessCell.frontVisibility === 1 ? Color.Black : Color.White) :
                Color.Transparent)// 设置背景颜色
                .borderRadius('50%')// 设置圆角
                .rotate({
                  // 设置旋转
                  x: 0,
                  y: 1,
                  z: 0,
                  angle: chessCell.rotationAngle, // 旋转角度
                  centerX: `${this.cellSize / 2}lpx`, // 中心点X坐标
                  centerY: `${this.cellSize / 2}lpx`, // 中心点Y坐标
                })
                .onClick(() => { // 单击事件处理
                  if (this.isAIPlaying) {
                    console.info(`ai正在落子,玩家不可继续落子`)
                    return;
                  }
                  if (chessCell.frontVisibility === 0) { // 没有棋子,需要落子
                    this.placeChessPiece(rowIndex, colIndex, chessCell)
                  }
                });
            });
          });
        }
        .width(`${(this.cellSize + this.cellSpacing * 2) * 8}lpx`) // 设置宽度
      }
      .padding(`${this.cellSpacing}lpx`)
      .backgroundColor(Color.Black)
 
      Row() {
        Text(`${this.isTwoPlayerMode? '双人游戏' : '单人游戏'}`)
          .height(50)
          .padding({ left: 10 })
          .fontSize(16)
          .textAlign(TextAlign.Start)
          .backgroundColor(0xFFFFFF)
        Toggle({ type: ToggleType.Switch, isOn: this.isTwoPlayerMode })
          .margin({ left: 200, right: 10 })
          .onChange((isOn: boolean) => {
            this.isTwoPlayerMode = isOn
          })
      }
      .backgroundColor(0xFFFFFF)
      .borderRadius(5)
 
      Button('重新开始').onClick(() => { // 按钮点击事件
        this.initGame()
      });
    }
    .height('100%').width('100%') // 设置高度和宽度
    .backgroundColor(Color.Orange)
  }
}

  

posted @   zhongcx  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示