赞
踩
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
在DevEco Studio中点击File -> New Project ->[Standard]Empty Ability->Next,Language 选择ETS语言,最后点击Finish即创建成功。
效果图如上可以分为两部分
1)首先在@entry组件入口build()中使用Stack作为容器,达到图片和文字堆叠的效果;
2)接着依次写入Image和Column包裹的两个Text组件;
- 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)
- }
- }
1)使用Grid网格容器来编写九宫格区域;
2)在GridItem中Stack容器依次添加方块背景图片和炸弹图片;
3)在visibility属性中用bombIndex变量值来决定炸弹显示的位置;
4)通过onClick点击事件和GestureGroup组合手势加入单击、双击和长按的监听事件;
- 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%')
1)通过 @CustomDialog 装饰器来创建自定义弹窗,使用方式可参考 自定义弹窗;
2)规则弹窗效果如下,弹窗组成由两个Text和两个Image竖向排列组成,所以我们可以在build()下使用Column容器来包裹,组件代码如下;
- @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)
- }
- }
3)在@entry创建CustomDialogController对象并传入弹窗所需参数,后面可通过该对象open()和close()方法进行打开和关闭弹窗;
- @Provide deviceList: RemoteDevice[] = []
- private ruleDialog: CustomDialogController = new CustomDialogController({
- builder: RuleDialog({
- invite: () => this.InvitePlayer(),
- confirm: () => this.startGame(),
- deviceList: this.deviceList
- }),
- autoCancel: false
- })
1)编写弹窗布局:将游戏失败文本、炸弹图片和再来一局按钮图片放置于Column容器中;
2)用变量来控制动画起始和结束的位置:用Flex容器包裹炸弹图片,并用@State
装饰变量toggle
,通过变量来动态修改Flex的direction属性;
- @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)
- }
3)设置动画效果:使用 animateTo 显式动画接口炸弹位置切换时添加动画,并且设置定时器定时执行动画;
- aboutToAppear() {
- this.setBombAnimate()
- }
-
- setBombAnimate() {
- let fun = () => {
- this.toggle = !this.toggle;
- }
- this.interval = setInterval(() => {
- animateTo({ duration: 1500, curve: Curve.Sharp }, fun)
- }, 1600)
- }
分布式流转需要在同一网络下通过 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设备信息列表。
项目实现分布式流转只需如下流程:
1)导入RemoteDeviceManager
import {RemoteDeviceManager} from './RemoteDeviceManager'
2)声明@Provide
装饰的设备列表变量deviceList
,和创建RemoteDeviceManager
实例。
- @Provide deviceList: RemoteDevice[] = []
- private remoteDm: RemoteDeviceManager = new RemoteDeviceManager(this.deviceList)
在生命周期aboutToAppear中,调用刷新设备列表和开始发现设备。
aboutToAppear定义:函数在创建自定义组件的新实例后,在执行其build函数之前执行。
- aboutToAppear() {
- this.remoteDm.refreshRemoteDeviceList() // 刷新设备列表
- this.remoteDm.startDeviceDiscovery() // 开始发现设备
- }
- 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!" })
- })
- }
从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);
- });
- });
- }
在声明周期aboutToDisappear进行注销监听。
aboutToDisappear定义:函数在自定义组件析构消耗之前执行。
- aboutToDisappear() {
- this.remoteDm.stopDeviceDiscovery() // 注销监听
- }
- 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)
- }
编写判断逻辑,用于不同的点击事件中调用。
- /**
- * 判断游戏输赢
- * @param operation 点击类型
- */
- judgeGame(operation:RuleType) {
- this.stopCountDown()
- if (operation != this.ruleText) {
- this.gameFail()
- } else {
- prompt.showToast({ message: "finish" })
- this.bombIndex = -1
- this.startAbilityRandom()
- }
- }
游戏失败,弹出游戏失败弹框。
- gameFail() {
- prompt.showToast({
- message: 'Game Fail'
- })
- CommonLog.info('gameFail');
- this.gameFailDialog.open()
- }
最后,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。
为了能够帮助大家快速掌握鸿蒙(Harmony NEXT)应用开发技术知识。在此给大家分享一下我结合鸿蒙最新资料整理出来的鸿蒙南北向开发学习路线以及整理的最新版鸿蒙学习文档资料。
这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料
获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
HarmonOS基础技能
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
OpenHarmony北向、南向开发环境搭建
获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。