鸿蒙HarmonyOS项目实战开辟:传炸弹小游戏

打印 上一主题 下一主题

主题 776|帖子 776|积分 2328

简介

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


目录

完整的项目布局目录如下
  1. ├─entry\src\main
  2. │     │  config.json // 应用配置
  3. │     ├─ets
  4. │     │  └─MainAbility
  5. │     │      │  app.ets //ets应用程序主入口
  6. │     │      └─pages
  7. │     │              CommonLog.ets // 日志类
  8. │     │              game.ets // 游戏首页
  9. │     │              RemoteDeviceManager.ets // 设备管理类
  10. │     └─resources // 静态资源目录
  11. │         ├─base
  12. │         │  ├─element
  13. │         │  ├─graphic
  14. │         │  ├─layout
  15. │         │  ├─media // 存放媒体资源
  16. │         │  └─profile
  17. │         └─rawfile
复制代码
开辟步骤

1. 新建OpenHarmony ETS项目

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

2. 编写游戏页面



效果图如上可以分为两部分
2.1 顶部状态提示栏

1)起首在@entry组件入口build()中使用Stack作为容器,达到图片和笔墨堆叠的效果;
2)接着依次写入Image和Column包裹的两个Text组件;
  1.   Stack() {
  2.      Image($r("app.media.title")).objectFit(ImageFit.Contain).height(120)
  3.      Column() {
  4.         Text(this.duration.toString() + 'ms').fontColor(Color.White)
  5.         Text(this.touchText).fontColor(Color.White)
  6.      }
  7.   }
复制代码
2.2 中间游戏炸弹九宫格区域

1)使用Grid网格容器来编写九宫格区域;
2)在GridItem中Stack容器依次添加方块配景图片和炸弹图片;
3)在visibility属性中用bombIndex变量值来决定炸弹显示的位置;
4)通过onClick点击事件和GestureGroup组合手势参加单击、双击和长按的监听事件;
  1. Stack() {
  2.      Image($r("app.media.background")).objectFit(ImageFit.Contain)
  3.      Grid() {
  4.          ForEach(this.grid, (item) => {
  5.              GridItem() {
  6.                  Stack() {
  7.                      Image($r("app.media.squares")).objectFit(ImageFit.Contain)
  8.                      Image($r("app.media.bomb"))
  9.                          .width('50%')
  10.                          .objectFit(ImageFit.Contain)
  11.                          .visibility(this.bombIndex == item ? Visibility.Visible : Visibility.Hidden)
  12.                          // 炸弹点击事件
  13.                          .onClick((event) => {
  14.                              // 单击
  15.                              this.judgeGame(RuleType.click)
  16.                          })
  17.                          .gesture(
  18.                          GestureGroup(GestureMode.Exclusive,
  19.                          LongPressGesture({ repeat: false })
  20.                              .onAction((event: GestureEvent) => {
  21.                                  // 长按
  22.                                  this.judgeGame(RuleType.longPress)
  23.                              }),
  24.                          TapGesture({ count: 2 })
  25.                              .onAction(() => {
  26.                                  // 双击
  27.                                  this.judgeGame(RuleType.doubleClick)
  28.                              })
  29.                          )
  30.                  }
  31.              }.forceRebuild(false)
  32.          }, item => item)
  33.      }
  34.      .columnsTemplate('1fr 1fr 1fr')
  35.      .rowsTemplate('1fr 1fr 1fr')
  36.      .columnsGap(10)
  37.      .rowsGap(10)
  38.      .width('90%')
  39.      .height('75%')
  40. }.width('80%').height('70%')
复制代码
3. 添加弹窗

3.1 创建规则游戏弹窗

1)通过 @CustomDialog 装饰器来创建自界说弹窗,使用方式可参考 自界说弹窗;
2)规则弹窗效果如下,弹窗构成由两个Text和两个Image竖向排列构成,以是我们可以在build()下使用Column容器来包裹,组件代码如下;



  1.    @CustomDialog
  2.    struct RuleDialog {
  3.       controller: CustomDialogController
  4.       confirm: () => void
  5.       invite: () => void
  6.       @Consume deviceList: RemoteDevice[]
  7.    
  8.       build() {
  9.          Column() {
  10.             Text('游戏规则').fontSize(30).margin(20)
  11.             Text('炸弹会随机出现在9个方块内,需要在规定时间内完成指定操作(点击、双击或长按),即可将炸弹传递给下一个人,小心炸弹可是会越来越快的喔!')
  12.                .fontSize(24).margin({ bottom: 10 })
  13.             Image($r("app.media.btn_start")).objectFit(ImageFit.Contain).height(80).margin(10)
  14.                .onClick(() => {
  15.                   console.info(TAG + 'Click start game')
  16.                   if (checkTrustedDevice(this.remoteDeviceModel)) {
  17.                      this.controller.close()
  18.                      this.confirm()
  19.                   }
  20.                })
  21.             Image($r("app.media.btn_Invite")).objectFit(ImageFit.Contain).height(80).margin(10)
  22.                .onClick(() => {
  23.                   this.invite()
  24.                })
  25.          }.width('90%')
  26.          .margin(20)
  27.          .backgroundColor(Color.White)
  28.       }
  29.    }
复制代码
3)在@entry创建CustomDialogController对象并传入弹窗所需参数,后面可通过该对象open()和close()方法进行打开和关闭弹窗;
  1. @Provide deviceList: RemoteDevice[] = []
  2. private ruleDialog: CustomDialogController = new CustomDialogController({
  3.    builder: RuleDialog({
  4.       invite: () => this.InvitePlayer(),
  5.       confirm: () => this.startGame(),
  6.       deviceList: this.deviceList
  7.    }),
  8.    autoCancel: false
  9. })
复制代码
3.2 创建游戏失败弹窗,并添加动画效果



1)编写弹窗布局:将游戏失败文本、炸弹图片和再来一局按钮图片放置于Column容器中;
2)用变量来控制动画起始和结束的位置:用Flex容器包裹炸弹图片,并用@State装饰变量toggle,通过变量来动态修改Flex的direction属性;
  1. @State toggle: boolean = true
  2. private controller: CustomDialogController
  3. @Consume deviceList: RemoteDevice[]
  4. private confirm: () => void
  5. private interval = null
  6. build() {
  7.    Column() {
  8.       Text('游戏失败').fontSize(30).margin(20)
  9.       Flex({
  10.          direction: this.toggle ? FlexDirection.Column : FlexDirection.ColumnReverse,
  11.          alignItems: ItemAlign.Center
  12.       })
  13.       {
  14.          Image($r("app.media.bomb")).objectFit(ImageFit.Contain).height(80)
  15.       }.height(200)
  16.       Image($r("app.media.btn_restart")).objectFit(ImageFit.Contain).height(120).margin(10)
  17.          .onClick(() => {
  18.                this.controller.close()
  19.                this.confirm()
  20.          })
  21.    }
  22.    .width('80%')
  23.    .margin(50)
  24.    .backgroundColor(Color.White)
  25. }
复制代码
3)设置动画效果:使用 animateTo 显式动画接口炸弹位置切换时添加动画,而且设置定时器定时执行动画;
  1. aboutToAppear() {
  2.    this.setBombAnimate()
  3. }
  4. setBombAnimate() {
  5.    let fun = () => {
  6.       this.toggle = !this.toggle;
  7.    }
  8.    this.interval = setInterval(() => {
  9.       animateTo({ duration: 1500, curve: Curve.Sharp }, fun)
  10.    }, 1600)
  11. }
复制代码
4. 添加分布式流转

分布式流转需要在同一网络下通过 DeviceManager组件 进行装备间发现和认证,获取到可信装备的deviceId调用 featureAbility.startAbility ,即可把应用程序流转到另一装备。
本来分布式流转应用流程如下:
1)创建DeviceManager实例;
2)调用实例的startDeviceDiscovery(),开始装备发现未信托装备;
3)设置装备状态监听on('deviceStateChange',callback),监听装备上下线状态;
4)设置装备状态监听on('deviceFound',callback),监听装备发现;
5)传入未信托装备参数,调用实例authenticateDevice方法,对装备进行PIN码认证;
6)如果已信托装备,可通过实例的getTrustedDeviceListSync()方法来获取装备信息;
7)将装备信息中的deviceId传入featureAbility.startAbility方法,实现流转;
8)流转接收方可通过featureAbility.getWant()获取到发送方携带的数据;
9)注销装备发现监听off('deviceFound');
10)注销装备状态监听off('deviceStateChange');
项目中将上面装备管理封装至RemoteDeviceManager,通过RemoteDeviceManager的四个方法来动态维护deviceList装备信息列表。


项目实现分布式流转只需如下流程:
4.1 创建RemoteDeviceManager实例

1)导入RemoteDeviceManager
  1. import {RemoteDeviceManager} from './RemoteDeviceManager'
复制代码
2)声明@Provide装饰的装备列表变量deviceList,和创建RemoteDeviceManager实例。
  1. @Provide deviceList: RemoteDevice[] = []
  2. private remoteDm: RemoteDeviceManager = new RemoteDeviceManager(this.deviceList)
复制代码
4.2 革新装备列表

在生命周期aboutToAppear中,调用革新装备列表和开始发现装备。
aboutToAppear界说:函数在创建自界说组件的新实例后,在执行其build函数之前执行。
  1. aboutToAppear() {
  2.     this.remoteDm.refreshRemoteDeviceList() // 刷新设备列表
  3.     this.remoteDm.startDeviceDiscovery() // 开始发现设备
  4. }
复制代码
4.3 装备认证

  1. invitePlayer(remoteDevice:RemoteDevice) {
  2.     if (remoteDevice.status == RemoteDeviceStatus.ONLINE) {
  3.         prompt.showToast({ message: "Already invited!" })
  4.         return
  5.     }
  6.     this.remoteDm.authDevice(remoteDevice).then(() => {
  7.         prompt.showToast({ message: "Invite success! deviceName=" + remoteDevice.deviceName })
  8.     }).catch(() => {
  9.         prompt.showToast({ message: "Invite fail!" })
  10.     })
  11. }
复制代码
4.4 跨装备流转

从deviceList中获取装备列表在线的装备Id,通过featureAbility.startAbility进行流转。
  1. async startAbilityRandom() {
  2.     let deviceId = this.getRandomDeviceId() // 随机获取设备id
  3.     CommonLog.info('featureAbility.startAbility deviceId=' + deviceId);
  4.     let bundleName = await getBundleName()
  5.     let wantValue = {
  6.         bundleName: bundleName,
  7.         abilityName: 'com.sample.bombgame.MainAbility',
  8.         deviceId: deviceId,
  9.         parameters: {
  10.             ongoing: true,
  11.             transferNumber: this.transferNumber + 1
  12.         }
  13.     };
  14.     featureAbility.startAbility({
  15.         want: wantValue
  16.     }).then((data) => {
  17.         CommonLog.info(' featureAbility.startAbility finished, ' + JSON.stringify(data));
  18.         featureAbility.terminateSelf((error) => {
  19.             CommonLog.info('terminateSelf finished, error=' + error);
  20.         });
  21.     });
  22. }
复制代码
4.5 注销监听

在声明周期aboutToDisappear进行注销监听。
aboutToDisappear界说:函数在自界说组件析构斲丧之前执行。
  1. aboutToDisappear() {
  2.     this.remoteDm.stopDeviceDiscovery() // 注销监听
  3. }
复制代码
5. 编写游戏逻辑

5.1 开始游戏

  1. startGame() {
  2.     CommonLog.info('startGame');
  3.     this.randomTouchRule() // 随机游戏点击规则
  4.     this.setRandomBomb() // 随机生成炸弹位置
  5.     this.stopCountDown() // 停止倒计时
  6.     if (this.transferNumber < 10) {
  7.         this.duration = 3000 - this.transferNumber * 100
  8.     } else {
  9.         this.duration = 2000
  10.     }
  11.     const interval: number = 500
  12.     // 开始倒计时
  13.     this.timer = setInterval(() => {
  14.         if (this.duration <= interval) {
  15.             this.duration = 0
  16.             clearInterval(this.timer)
  17.             this.timer = null
  18.             this.gameFail()
  19.         } else {
  20.             this.duration -= interval
  21.         }
  22.     }, interval)
  23. }
复制代码
5.2 判定输赢

编写判定逻辑,用于不同的点击事件中调用。
  1. /**
  2. * 判断游戏输赢
  3. * @param operation 点击类型
  4. */
  5. judgeGame(operation:RuleType) {
  6.    this.stopCountDown()
  7.    if (operation != this.ruleText) {
  8.       this.gameFail()
  9.    } else {
  10.       prompt.showToast({ message: "finish" })
  11.       this.bombIndex = -1
  12.       this.startAbilityRandom()
  13.    }
  14. }
复制代码
5.3 游戏失败

游戏失败,弹出游戏失败弹框。
  1. gameFail() {
  2.     prompt.showToast({
  3.         message: 'Game Fail'
  4.     })
  5.     CommonLog.info('gameFail');
  6.     this.gameFailDialog.open()
  7. }
复制代码
最后,有很多小同伴不知道学习哪些鸿蒙开辟技术?不知道需要重点掌握哪些鸿蒙应用开辟知识点?而且学习时频繁踩坑,终极浪费大量时间。以是有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。 
为了能够资助大家快速掌握鸿蒙(Harmony NEXT)应用开辟技术知识。在此给大家分享一下我结合鸿蒙最新资料整理出来的鸿蒙南北向开辟学习门路以及整理的最新版鸿蒙学习文档资料。
这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开辟必掌握的焦点知识要点,内容包含了ArkTS、ArkUI开辟组件、Stage模型、多端部署、分布式应用开辟、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开辟、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。
盼望这一份鸿蒙学习资料能够给大家带来资助,有需要的小同伴自行领取,限时开源,先到先得~无套路领取!!
如果你是一名有履历的资深Android移动开辟、Java开辟、前端开辟、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料
 获取这份完整版高清学习门路,请点击→纯血版全套鸿蒙HarmonyOS学习资料
鸿蒙(Harmony NEXT)最新学习门路




  •  HarmonOS基础技能



  • HarmonOS就业必备技能 

  •  HarmonOS多媒体技术



  • 鸿蒙NaPi组件进阶



  • HarmonOS高级技能



  • 初识HarmonOS内核 

  • 实战就业级装备开辟

 有了门路图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套体系性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开辟入门讲授视频,内容包含:ArkTS、ArkUI、Web开辟、应用模型、资源分类…等知识点。
获取以上完整版高清学习门路,请点击→纯血版全套鸿蒙HarmonyOS学习资料
《鸿蒙 (OpenHarmony)开辟入门讲授视频》


《鸿蒙生态应用开辟V2.0白皮书》


《鸿蒙 (OpenHarmony)开辟基础到实战手册》

OpenHarmony北向、南向开辟环境搭建

 《鸿蒙开辟基础》



  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开辟
  • .……

 《鸿蒙开辟进阶》



  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开辟
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 使命管理
  • WebGL
  • 国际化开辟
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙体系移植和裁剪定制
  • ……

《鸿蒙进阶实战》



  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个时机。只有积极应对变化,不断学习和提拔本身,他们才能在这个厘革的时代中立于不败之地。 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表