谷动谷力

标题: 基于OpenHarmony系统从零开发传炸弹小游戏 [打印本页]

作者: 鸣涧    时间: 2022-8-25 23:30
标题: 基于OpenHarmony系统从零开发传炸弹小游戏
基于OpenHarmony系统从零开发传炸弹小游戏
简介

demo基于OpenHarmony系统使用ETS语言进行编写,在邀请用户进行设备认证后,用户根据操作提示完成相应操作,然后通过分布式流转实现随机传递炸弹的效果。



工程目录

完整的项目结构目录如下
├─entry\src\main
│     │  config.json // 应用配置
│     ├─ets
│     │  └─MainAbility
│     │      │  app.ets //ets应用程序主入口
│     │      └─pages
│     │              CommonLog.ets // 日志类
│     │              game.ets // 游戏首页
│     │              RemoteDeviceManager.ets // 设备管理类
│     └─resources // 静态资源目录
│         ├─base
│         │  ├─element
│         │  ├─graphic
│         │  ├─layout
│         │  ├─media // 存放媒体资源
│         │  └─profile
│         └─rawfile
(左右移动查看全部内容)


开发步骤

1、新建OpenHarmony ETS项目:
在DevEco Studio中点击File -> New Project ->[Standard]Empty Ability->Next,Language 选择ETS语言,最后点击Finish即创建成功。


2、编写游戏页面


效果图如上可以分为两部分

2.1 顶部状态提示栏

Stack() {
     Image($r("app.media.title")).objectFit(ImageFit.Contain).height(120)
     Column() {
        Text(this.duration.toString() + 'ms').fontColor(Color.White)
        Text(this.touchText).fontColor(Color.White)
     }
  }
(左右移动查看全部内容)

2.2 中间游戏炸弹九宫格区域
Stack() {
   Image($r("app.media.background")).objectFit(ImageFit.Contain)
   Grid() {
     ForEach(this.grid, (item) => {
       GridItem() {
         Stack() {
           Image($r("app.media.squares")).objectFit(ImageFit.Contain)
           Image($r("app.media.bomb"))
             .width('50%')
             .objectFit(ImageFit.Contain)
             .visibility(this.bombIndex == item ? Visibility.Visible : Visibility.Hidden)
             // 炸弹点击事件
             .onClick((event) => {
               // 单击
               this.judgeGame(RuleType.click)
             })
             .gesture(
             GestureGroup(GestureMode.Exclusive,
             LongPressGesture({ repeat: false })
               .onAction((event: GestureEvent) => {
                 // 长按
                 this.judgeGame(RuleType.longPress)
               }),
             TapGesture({ count: 2 })
               .onAction(() => {
                 // 双击
                 this.judgeGame(RuleType.doubleClick)
               })
             )
         }
       }.forceRebuild(false)
     }, item => item)
   }
   .columnsTemplate('1fr 1fr 1fr')
   .rowsTemplate('1fr 1fr 1fr')
   .columnsGap(10)
   .rowsGap(10)
   .width('90%')
   .height('75%')
}.width('80%').height('70%')
(左右移动查看全部内容)

3、添加弹窗
3.1 创建规则游戏弹窗


@CustomDialog
   struct RuleDialog {
      controller: CustomDialogController
      confirm: () => void
      invite: () => void
      @consume deviceList: RemoteDevice[]

      build() {
         Column() {
            Text('游戏规则').fontSize(30).margin(20)
            Text('炸弹会随机出现在9个方块内,需要在规定时间内完成指定操作(点击、双击或长按),即可将炸弹传递给下一个人,小心炸弹可是会越来越快的喔!')
               .fontSize(24).margin({ bottom: 10 })
            Image($r("app.media.btn_start")).objectFit(ImageFit.Contain).height(80).margin(10)
               .onClick(() => {
                  console.info(TAG + 'Click start game')
                  if (checkTrustedDevice(this.remoteDeviceModel)) {
                     this.controller.close()
                     this.confirm()
                  }
               })
            Image($r("app.media.btn_Invite")).objectFit(ImageFit.Contain).height(80).margin(10)
               .onClick(() => {
                  this.invite()
               })
         }.width('90%')
         .margin(20)
         .backgroundColor(Color.White)
      }
   }
(左右移动查看全部内容)

@Provide deviceList: RemoteDevice[] = []
private ruleDialog: CustomDialogController = new CustomDialogController({
   builder: RuleDialog({
      invite: () => this.InvitePlayer(),
      confirm: () => this.startGame(),
      deviceList: this.deviceList
   }),
   autoCancel: false
})
(左右移动查看全部内容)

3.2 创建游戏失败弹窗,并添加动画效果


@State toggle: boolean = true
private controller: CustomDialogController
@Consume deviceList: RemoteDevice[]
private confirm: () => void
private interval = null

build() {
   Column() {
      Text('游戏失败').fontSize(30).margin(20)
      Flex({
         direction: this.toggle ? FlexDirection.Column : FlexDirection.ColumnReverse,
         alignItems: ItemAlign.Center
      })
      {
         Image($r("app.media.bomb")).objectFit(ImageFit.Contain).height(80)
      }.height(200)

      Image($r("app.media.btn_restart")).objectFit(ImageFit.Contain).height(120).margin(10)
         .onClick(() => {
               this.controller.close()
               this.confirm()
         })
   }
   .width('80%')
   .margin(50)
   .backgroundColor(Color.White)
}
(左右移动查看全部内容)

aboutToAppear() {
   this.setBombAnimate()
}

setBombAnimate() {
   let fun = () => {
      this.toggle = !this.toggle;
   }
   this.interval = setInterval(() => {
      animateTo({ duration: 1500, curve: Curve.Sharp }, fun)
   }, 1600)
}
(左右移动查看全部内容)

4、添加分布式流转
分布式流转需要在同一网络下通过 DeviceManager组件 进行设备间发现和认证,获取到可信设备的deviceId调用 featureAbility.startAbility ,即可把应用程序流转到另一设备。

原本分布式流转应用流程如下:

项目中将上面设备管理封装至RemoteDeviceManager,通过RemoteDeviceManager的四个方法来动态维护deviceList设备信息列表。


项目实现分布式流转只需如下流程:
4.1 创建RemoteDeviceManager实例
import {RemoteDeviceManager} from './RemoteDeviceManager'
(左右移动查看全部内容)

@Provide deviceList: RemoteDevice[] = []
private remoteDm: RemoteDeviceManager = new RemoteDeviceManager(this.deviceList)
(左右移动查看全部内容)

4.2 刷新设备列表
在生命周期aboutToAppear中,调用刷新设备列表和开始发现设备。

aboutToAppear定义:函数在创建自定义组件的新实例后,在执行其build函数之前执行。
aboutToAppear() {
  this.remoteDm.refreshRemoteDeviceList() // 刷新设备列表
  this.remoteDm.startDeviceDiscovery() // 开始发现设备
}
(左右移动查看全部内容)

4.3 设备认证
invitePlayer(remoteDevice:RemoteDevice) {
  if (remoteDevice.status == RemoteDeviceStatus.ONLINE) {
    prompt.showToast({ message: "Already invited!" })
    return
  }
  this.remoteDm.authDevice(remoteDevice).then(() => {
    prompt.showToast({ message: "Invite success! deviceName=" + remoteDevice.deviceName })
  }).catch(() => {
    prompt.showToast({ message: "Invite fail!" })
  })
}
(左右移动查看全部内容)

4.4 跨设备流转
从deviceList中获取设备列表在线的设备Id,通过featureAbility.startAbility进行流转。
async startAbilityRandom() {
  let deviceId = this.getRandomDeviceId() // 随机获取设备id
  CommonLog.info('featureAbility.startAbility deviceId=' + deviceId);
  let bundleName = await getBundleName()
  let wantValue = {
    bundleName: bundleName,
    abilityName: 'com.sample.bombgame.MainAbility',
    deviceId: deviceId,
    parameters: {
      ongoing: true,
      transferNumber: this.transferNumber + 1
    }
  };
  featureAbility.startAbility({
    want: wantValue
  }).then((data) => {
    CommonLog.info(' featureAbility.startAbility finished, ' + JSON.stringify(data));
    featureAbility.terminateSelf((error) => {
      CommonLog.info('terminateSelf finished, error=' + error);
    });
  });
}
(左右移动查看全部内容)

4.5 注销监听
在声明周期aboutToDisappear进行注销监听。

aboutToDisappear定义:函数在自定义组件析构消耗之前执行。
aboutToDisappear() {
  this.remoteDm.stopDeviceDiscovery() // 注销监听
}
(左右移动查看全部内容)

5、编写游戏逻辑
5.1 开始游戏
startGame() {
  CommonLog.info('startGame');
  this.randomTouchRule() // 随机游戏点击规则
  this.setRandomBomb() // 随机生成炸弹位置
  this.stopCountDown() // 停止倒计时
  if (this.transferNumber < 10) {
    this.duration = 3000 - this.transferNumber * 100
  } else {
    this.duration = 2000
  }
  const interval: number = 500
  // 开始倒计时
  this.timer = setInterval(() => {
    if (this.duration <= interval) {
      this.duration = 0
      clearInterval(this.timer)
      this.timer = null
      this.gameFail()
    } else {
      this.duration -= interval
    }
  }, interval)
}
(左右移动查看全部内容)

5.2 判断输赢
编写判断逻辑,用于不同的点击事件中调用。
/**
* 判断游戏输赢
* @param operation 点击类型
*/
judgeGame(operation:RuleType) {
   this.stopCountDown()
   if (operation != this.ruleText) {
      this.gameFail()
   } else {
      prompt.showToast({ message: "finish" })
      this.bombIndex = -1
      this.startAbilityRandom()
   }
}
(左右移动查看全部内容)

5.3 游戏失败
游戏失败,弹出游戏失败弹框。
gameFail() {
  prompt.showToast({
    message: 'Game Fail'
  })
  CommonLog.info('gameFail');
  this.gameFailDialog.open()
}
(左右移动查看全部内容)


项目下载和导入

项目仓库地址:https://gitee.com/openharmony-si ... ertainment/BombGame

1)git下载
git clone https://gitee.com/openharmony-sig/knowledge_demo_temp.git
(左右移动查看全部内容)

2)项目导入
打开DevEco Studio,点击File->Open->下载路径/FA/Entertainment/BombGame


约束与限制

1、设备编译约束
润和HiSpark Taurus AI Camera(Hi3516d)开发板套件:

润和大禹系列HH-SCDAYU200开发套件:

2、应用编译约束







欢迎光临 谷动谷力 (http://bbs.sunsili.com/) Powered by Discuz! X3.2