0
点赞
收藏
分享

微信扫一扫

『江鸟中原』鸿蒙扫雷小游戏

一.前言

     本学期通过对鸿蒙开发的学习,做一个简单的鸿蒙小游戏作为此次学习的大作业。很常见的小游戏扫雷,由于时间有限,只实现了扫雷的玩法,长按事件,不同困难程度,游戏的终止。

二.环境

这个小游戏是基于华为鸿蒙操作系统(HarmonyOS)和鸿蒙应用开发工具(Huawei DevEco Studio)实现的。语言用的是ArkTS。

三.实现思路

1 .用二维数组来保存数据,-1表示雷

2. -1随机存储在二维数组中,先以简单难度5 * 5的二维数组展示,雷的个数为5个,根据难度的选择,二维数组的大小会随之改变,雷的个数也会改变。

3.算法实现雷周围的元素数字为雷的个数

4.构造二维数组的button对应创建好的二维数组

5 .点击0的时候将与0相邻的数字会被显示出来以及所有的0会变成空白的

6 .点击非0数字不包含-1只展示当前数字

7.长按可以选择旗帜或者问号

8.点击雷结束游戏,若成功则会显示成功

四.代码解析

1.创建一个新的项目

打开DevEco Studio,选择“Create HarmonyOS Project”,然后选择“Empty Ability”模板,点击“Next”。

『江鸟中原』鸿蒙扫雷小游戏_二维数组

2.创建项目构建

其中MincBean,MineClearData为实体类以及初始化数据的类,EntryAbility是程序入口类,index是页面。

『江鸟中原』鸿蒙扫雷小游戏_二维数组_02

3.创建MincBean实体类

在src->main->ets->common 下面创建bean文件夹,在文件夹下创建MincBean.ets文件

export class MineBean {
  row: number;
  col: number;
  mineCounts: number;
  time: number;
  rowLayout: string;
  colLayout: string;
  gridHeight: string;

  constructor(row: number, col: number, mineCounts: number, time: number, rowLayout: string, colLayout: string, gridHeight: string) {
    this.row = row;
    this.col = col;
    this.mineCounts = mineCounts;
    this.time = time;
    this.rowLayout = rowLayout;
    this.colLayout = colLayout;
    this.gridHeight = gridHeight;
  }
}

4.创建程序入口类

在src->main->ets下面创建entryability文件夹,在文件夹下创建EntryAbility.ts文件

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy() {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }

  onWindowStageDestroy() {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground() {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground() {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

5.创建二维数组

创建二维数组,生成并记录雷的位置,以及生成雷周边的数字,算法实现雷周围的元素数字为雷的个数

init() {
    // 初始化二维数组
    for (let i = 0; i < this.row; i++) {
      this.data[i] = new Array(this.col);
      this.data[i].fill(0);
    }
    // 记录雷的位置
    let mineArr = new Array();
    // 生成随机数表示雷的位置
    for (var i = 0; i < this.mineCount; i++) {
      let tempRow = this.getRandom(0, this.row - 1);
      let tempCol = this.getRandom(0, this.col - 1);
      if (this.data[tempRow][tempCol] == -1) {
        i--;
        continue;
      }
      mineArr.push([tempRow, tempCol]);
      this.data[tempRow][tempCol] = -1;
    }
    this.clicked = this.col * this.row - this.mineCount;
    console.log(JSON.stringify(this.data))
    // 生成雷周围的数字
    for (let i = 0; i < mineArr.length; i++) {
      let temp = mineArr[i];
      let tempRow = temp[0];
      let tempCol = temp[1];
      let arr = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]];
      for (let i = 0; i < arr.length; i++) {
        let nx = tempRow + arr[i][0];
        let ny = tempCol + arr[i][1];
        if (nx < 0 || nx >= this.row || ny < 0 || ny >= this.col || this.data[nx][ny] == -1) {
          continue;
        }
        this.data[nx][ny]++;
      }
    }
    console.log(JSON.stringify(this.data))
    return this.data;
  }

  getRandom(minValue: number, maxValue: number): number {
    let temp = maxValue - minValue + 1;
    return Math.floor(Math.random() * temp) + minValue
  }

  getShowContent() {
    this.init();
    // 初始化二维数组
    for (let i = 0; i < this.row; i++) {
      this.showContent[i] = new Array(this.col);
      this.showContent[i].fill(undefined);
    }
  }

判断点击的格子中的数字是否为0,为0的时候将与0相邻的数字会被显示出来以及所有的0会变成空白的,不为0则显示点击的数字

changeButtonContent(num: any): any {
    if (num == 0) {
      return undefined;
    } else if (num === undefined) {
      return undefined;
    } else if (num == -1) {
      return $r('app.media.boom')
    }
    return JSON.stringify(num);
  }

  getZero(i: number, j: number) {
    let arr = [[1, 0], [-1, 0], [0, -1], [0, 1]]
    let list = [];
    list.push([i, j]);
    while(list.length != 0) {
      let temp = list.shift();
      this.showContent[temp[0]][temp[1]] = 0;
      for (let i = 0; i < arr.length; i++) {
        let nx = temp[0] + arr[i][0];
        let ny = temp[1] + arr[i][1];
        if (nx < 0 || nx >= this.row || ny < 0 || ny >= this.col) {
          continue;
        }
        if (this.data[nx][ny] == 0 && this.showContent[nx][ny] != 0) {
          list.push([nx, ny]);
        }
        if ((this.data[nx][ny] !== 0 || this.data[nx][ny] !== -1) && this.showContent[nx][ny] == undefined) {
          this.showContent[nx][ny] = this.data[nx][ny];
        }
      }
      console.log(JSON.stringify(list.length + '  ' + list.toString()));
    }
  }

实现结果如下图

『江鸟中原』鸿蒙扫雷小游戏_二维数组_03

6.长按事件以及添加倒计时

长按动作的触发

.gesture(
              LongPressGesture({ repeat: false })
                // 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
                .onAction((event: GestureEvent) => {
                  if (this.showContent[i][j] == undefined || this.showContent[i][j] == 'mark' || this.showContent[i][j] == 'flag') {
                    this.positionX = JSON.stringify(event.fingerList[0].globalX - 30);
                    this.positionY = JSON.stringify(event.fingerList[0].globalY - 30);
                    console.log(`${this.positionX} ${this.positionY}`)
                    this.isShowPick = true;
                    this.dataI = i;
                    this.dataJ = j;
                  }

                  console.log(JSON.stringify(this.positionX));
                  console.log(JSON.stringify(event.target.area.globalPosition.x));
                  console.log(JSON.stringify(event))
                  console.log('chang an');
                })
                  // 长按动作一结束触发
                .onActionEnd(() => {
                  this.timeOut();
                  console.log('chang an');
                })

长按后可选择旗帜或者问号

 GridItem() {
            Button( {
              type: ButtonType.Normal
            }) {
              if (this.showContent[i][j] == -1) {
                Image($r('app.media.boom'))
                  .objectFit(ImageFit.Fill)
              } else if (this.showContent[i][j] == 0) {

              } else if (this.showContent[i][j] == this.fruits[1]) {
                Image($r('app.media.flag'))
                  .objectFit(ImageFit.Fill)
              } else if (this.showContent[i][j] == this.fruits[2]) {
                Image($r('app.media.mark'))
                  .objectFit(ImageFit.Fill)
              } else {
                Text(JSON.stringify(num)).fontColor(Color.Black).fontSize('24fp')
              }
            }
            .width('100%')
            .height('100%')
            .backgroundColor(this.changeButtonColor(i, j))
            .onClick(() => {
              if (this.showContent[i][j] !== undefined && this.showContent[i][j] != 'mark' && this.showContent[i][j] != 'flag') {
                return
              }
              if (this.data[i][j] == 0) {
                this.getZero(i, j)
              }
              this.showContent[i][j] = this.data[i][j];
              if (this.showContent[i][j] == -1) {
                this.isShow = !this.isShow;
                this.alertDialogComponent('failed');
                return;
              }
              let count = 0;
              for (let i = 0; i < this.showContent.length; i++) {
                for (let j = 0; j < this.showContent[i].length; j++) {
                  if (this.showContent[i][j] != undefined && this.showContent[i][j] != this.fruits[1]
                  && this.showContent[i][j] != this.fruits[2]) {
                    count++;
                  }
                }
              }

添加倒计时

 /**
   * 控制长按弹出框3秒后消失
   */
  timeOut() {
    var timeoutID = setTimeout(() => {
      this.isShowPick = false;
    }, 3000);
  }

  /**
   * 倒计时,当时间到0时失败
   */

实现结果如下图

『江鸟中原』鸿蒙扫雷小游戏_二维数组_04

7.困难程度选择

在src->main->ets 下面创建view文件夹,在文件夹下创建DifficultSelectionDialogView.ets文件

export struct DifficultySelectionDialogView {
  @Link difficulty: number;
  private level: string[];
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
  build() {
    Column() {
      Text('难度选择').fontSize(20).margin({ top: 10, bottom: 10 })
      Row() {
        Slider({
          value: this.difficulty,
          min: 0,
          max: 3,
          style: SliderStyle.InSet
        })
          .width('80%')
          .blockColor('#df5a9f30')
          .trackColor('#ADD8E6')
          .selectedColor('#a96b7fc1')
          .showTips(true)
          .onChange((value: number, mode: SliderChangeMode) => {
            this.difficulty = value
            console.info('value:' + value + 'mode:' + mode.toString())
          })
        Text(this.level[this.difficulty])
          .fontSize('12fp')
      }

      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Button('关闭')
          .onClick(() => {
            this.controller.close()
          })
          .backgroundColor(Color.Blue)
          .fontColor(Color.Black)
      }.margin({ bottom: 10 })
    }
  }
}

在src->main->ets 下面创建pages文件夹,在文件夹下创建index.ets文件

本段代码主要是设置困难选择页面的实现

 build() {
    Row() {
      Stack() {
        Column() {
          Row({space: 5}) {
            Text(`级别: ${this.level[this.difficulty]}`)
              .fontSize('22vp')
              .fontWeight(FontWeight.Bolder)
            Button('开始')
              .onClick(() => {
                this.countDown();
              })
            Button('难度选择')
              .fontSize(24)
              .fontWeight(FontWeight.Medium)
              .onClick(() => {
                this.dialogController.open();
              })
          }
          .margin('10vp')

          Text('倒计时:' + JSON.stringify(this.time))
            .fontSize(35)
            .fontWeight(FontWeight.Medium)
          if (this.isShow) {
            this.gridItemContent();
          } else {
            this.gridItemContent();
          }
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Start)

        if (this.isShowPick) {
          Column() {
            Image($r('app.media.flag'))
              .width('70vp')
              .height('75vp')
              .objectFit(ImageFit.Fill)
              .onClick(() => {
                this.showContent[this.dataI][this.dataJ] = 'flag';
                this.isShowPick = false;
                this.isShow = !this.isShow;
              })
            Image($r('app.media.mark'))
              .width('70vp')
              .height('75vp')
              .objectFit(ImageFit.Fill)
              .onClick(() => {
                this.showContent[this.dataI][this.dataJ] = 'mark';
                this.isShowPick = false;
                this.isShow = !this.isShow;
              })
          }
          .width('70vp')
          .height('150vp')
          .position({x: this.positionX, y: this.positionY})
        }
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .alignItems(VerticalAlign.Top)
  }

实现结果如下

『江鸟中原』鸿蒙扫雷小游戏_二维数组_05


『江鸟中原』鸿蒙扫雷小游戏_二维数组_06

『江鸟中原』鸿蒙扫雷小游戏_二维数组_07

『江鸟中原』鸿蒙扫雷小游戏_二维数组_08

8.游戏终止

alertDialogComponent(message: string) {
    clearInterval(this.countDownTime);
    AlertDialog.show(
      {
        title: '',
        message: message,
        autoCancel: true,
        alignment: DialogAlignment.Center,
        offset: { dx: 0, dy: -20 },
        gridCount: 3,
        confirm: {
          value: '重新开始',
          action: () => {
            this.getShowContent();
            this.isShow = !this.isShow;
            this.time = this.allMineData[this.difficulty].time;
            this.countDown();
          }
        },
        cancel: () => {
          this.getShowContent();
          this.isShow = !this.isShow;
          console.info('Closed callbacks')
        }
      }
    )
  }//终止

实现结果如下

『江鸟中原』鸿蒙扫雷小游戏_二维数组_09

五.总结

本文是使用ArkTS语言编写的扫雷小游戏鸿蒙开发,主要参看网上相关的视频以及相关资料,本文尚有不足,比如这里的终止游戏界面,只实现了失败或者成功后继续开始游戏,并不能不继续开始游戏。望谅解,请指正。

文本到此完毕,有疑问的请在评论区留言交流,谢谢阅读。

举报

相关推荐

0 条评论