一、简介

继《OpenHarmony有氧拳击设备端的开发》后,本次为大家带来酷炫的应用端开发。如下,开发者伴随着音乐,律动出拳后,那开发板屡屡播放“挨打”效果,这究竟是怎么一回事?让我们一探背后原理。

这款拳击游戏开始时会播放音乐,然后以随机速度下落“击拳方块”。当小哥哥在击拳区域内挥拳时,游戏会判断方块的位置,根据不同位置确定播放普通击中或完美击中的动画效果。

二、动画

游戏中一共使用两种动画:属性动画和Lottie动画,分别实现下落和击中的效果。“击拳方块”下落效果是利用属性动画进行修改偏移量来实现。游戏同时设置定时器,定时获取挥拳状态和“击拳方块”的所处位置,用于判断当前挥拳是否得分。若得分则根据击中区间来播放不同效果的Lottie动画。

三、“下落”动画

1、属性动画介绍

从上图可以看到,游戏中“击拳方块”是自上而下匀速移动。这种简单控制通用属性进行动画变化的动画,便很适合使用属性动画来实现。属性动画是指组件的通用属性发生变化时,会根据开始状态和通用属性改变后的状态作为动画关键帧,在指定时间内实现渐变效果。换言之我们只需要确定设置好组件在动画结束时的组件属性,然后调用animateTo(value: AnimationOptions, event: ()=> void),即可创建属性动画。

AnimationOptions对象说明

● 属性

● 接口

2、动画实现

编写“击拳方块”UI组件,并将组件的相对布局偏移量offset属性,绑定到@state leftY1变量中,那么通过修改leftY1的值即可实现修改组件所在位置。


@State leftY1: string = '50%'
@Builder LeftBoxing(offsetY: string) {
Image($r('app.media.icon_boxing_left'))
.width(144)
.height(110)
.offset({ x: "-30%", y: offsetY })
.touchable(true)
}
build() {
Stack() {
// .....
// 左侧
this.LeftBoxing(this.leftY1)
// .....
}

  

3、创建动画

调用animateTo显式动画来播放动画实现单个“击拳方块”自上而下地移动,再通过设置delay参数实现4个“击拳方块”按顺序分别移动。

  async leftAnimate(){
// 设置图标下滑动画
// 动画持续时间
let leftDuration = this.getRandomDuration()
this.leftDuration = leftDuration
// 延迟时长
let leftDelay = leftDuration / (this.boxingCount - 1)
// 设置开始时间
let now = new Date
this.animateLeftTimestamp = now.getTime()
// 左侧animateTo动画
animateTo({ duration: leftDuration, curve: Curve.Linear,delay:0 * leftDelay ,iterations: 1 }, () => {
this.leftY1 = "50%"
})
animateTo({ duration: leftDuration, curve: Curve.Linear,delay:1 * leftDelay, iterations: 1 }, () => {
this.leftY2 = "50%"
})
animateTo({ duration: leftDuration, curve: Curve.Linear,delay:2 * leftDelay, iterations: 1 }, () => {
this.leftY3 = "50%"
})
animateTo({ duration: leftDuration, curve: Curve.Linear,delay:3 * leftDelay, iterations: 1 }, () => {
this.leftY4 = "50%"
})
let totalTime = leftDuration + 3 * leftDelay
await this.sleep(totalTime)
this.resetAnimate(true)
this.leftAnimate()
}

  

4、设置击中区域监听

设置定时器定时查询当前是否挥拳,若检测到挥拳再通过计算当前动画运行时间来判断“击拳方块”位置,从而执行击中或完美击中的逻辑,以下为监听逻辑。

  setScoreListen(){
this.intervalNumber = setInterval(async()=>{
let res = await BoxingGameNAPI.recvMsg();
if(res?.message.length > 0){
if(res.message.includes('left') && !this.leftAnimateLock){
// 检测到左手挥拳
this.judgeLeft()
}
}
},200)
} judgeLeft(){
let nowTime = new Date().getTime()
// 首次抵达目标顶部时间
let firstTime = this.animateLeftTimestamp + (this.percentToPoint(this.targetOffsetY)+this.percentToPoint('50%') - this.percentToPoint('10%')) * this.leftDuration
// 结束时间
let endTime = this.animateLeftTimestamp + this.leftDuration * 2
if(nowTime > firstTime - 200 && nowTime < endTime){
// 得分时间界限
let leftDelay = this.leftDuration /(this.boxingCount -1 )
let handleTime = (nowTime - firstTime) % leftDelay
let judgeTime = this.leftDuration /6
CommonLog.info(TAG,`leftDelay:${leftDelay},handleTime:${handleTime},judgeTime:${judgeTime}`)
// 完美击中
if (judgeTime/4 < handleTime && handleTime < (judgeTime *(3/4))) { }else if(handleTime < judgeTime){
// 普通击中
}else{
// 不得分
}
}else{
// 未抵达区域
}
}

  

四、击中动画

像前文提到的“下落”动画适合使用属性动画,那么当我们需要实现更复杂,如上图的动画效果时,该如何来实现呢?

Lottie介绍

Lottie是一款能够为应用程序添加动画的开源组件,它可以解析AE(After Effects)导出的json文件,让复杂的动画资源轻松运行在应用程序中。如图所示,动画文件通过AE的bodymovin插件将动画转换成通用的json格式描述文件后,应用开发者只需使用Lottie解析json文件,就能将动画绘制出来。

Lottie优点:

1. 只需使用Lottie解析json文件就能实现动画的加载,基本上实现了0代码开发;

2.  应用开发者可以通过修改json文件的参数,将动画运行到不同的应用程序中,实现动画的一次设计多端使用;

3. 应用开发者可从网络如https://lottiefiles.com/直接下载json文件,实时更新动画资源;

4. Lottie基于canvas画布进行基础的2D渲染,让动画流畅度更高;

5. Lottie可以将UX设计师给出的复杂动画效果100%还原到应用程序中 ;

6. Lottie提供了丰富的API,让开发者能轻松控制动画,大大提高了开发效率。

如何使用Lottie?

1. 导入Lottie

在Terminal窗口使用npm install @ohos/lottieETS命令下载Lottie,并在页面中导入@ohos/lottieETS,如下:

import lottie from '@ohos/lottieETS'

  

放置动画资源

将After Effects导出的json动画资源文件保存到项目common/lottie路径中,具体路径如下:entry/src/main/ets/MainAbility/common/lottie/animation.json

2. 创建Lottie动画

Lottie基于canvas画布进行基础的2D渲染,创建canvas画布后设置相关播放参数即可创建并播放Lottie动画,Lottie更多信息可参考Lottie接口。

创建canvas画布:

    @Builder TargetArea(controller:CanvasRenderingContext2D,lottieName:string) {
Stack() {
Canvas(controller)
.aspectRatio(1)
.width(300)
.offset({ y: this.targetOffsetY })
.onAppear(() => { })
Animator('__lottie_ets') // declare Animator('__lottie_ets') when use lottie
}.height('100%').width(220)
}

  

设置Lottie动画参数:

setLottie(controller:CanvasRenderingContext2D,lottieName:string,animatePath:string){
lottie.loadAnimation({
container: controller,
renderer: 'canvas',
loop: false,
autoplay: false,
name: lottieName,
path: animatePath,
})
lottie.setSpeed(1,lottieName)
}

  

在“下落”动画击拳监听中加入播放不同效果的Lottie动画逻辑:

  judgeLeft(){
......
if(nowTime > firstTime - 200 && nowTime < endTime){
......
// 完美击中
if (judgeTime/4 < handleTime && handleTime < (judgeTime *(3/4))) {
lottie.destroy('animate_left')
this.setLottie(this.controllerLeft,'animate_left',this.animatePerfectPath)
lottie.play('animate_left') // 播放完美击中动画
// 等动画执行完成后才能进入下一次挥拳判定
this.leftAnimateLock = true
setTimeout(()=>{
lottie.stop()
lottie.destroy('animate_left')
this.leftAnimateLock = false
},this.lottieDuration)
}else if(handleTime < judgeTime){
// 击中
lottie.destroy('animate_left')
this.setLottie(this.controllerLeft,'animate_left',this.animateJustPath)
lottie.play('animate_left')// 播放击中动画
this.leftAnimateLock = true
setTimeout(()=>{
lottie.stop()
lottie.destroy('animate_left')
this.leftAnimateLock = false
},this.lottieDuration)
}
}
}

  

五、总结

本文主要讲述了拳击互动游戏中,如何使用属性动画实现简单属性变化的动画效果,如游戏中“击拳方块”自上往下移动;使用Lottie组件实现复杂绚丽的动画效果,如游戏中的击拳效果。

本样例是OpenHarmony知识体系工作组(相关链接在文章末尾)为广大开发者分享的样例。知识体系工作组结合日常生活,给开发者规划了各种场景的Demo样例,如智能家居场景、影音娱乐场景、运动健康场景等。欢迎广大开发者一同参与OpenHarmony的开发,更加完善样例,相互学习,相互进步。

六、参考链接

本样例代码下载链接

https://growing.openharmony.cn/mainPlay/detail?sampleId=4070

属性动画

https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/reference/arkui-ts/ts-animatorproperty.md/

https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/reference/arkui-ts/ts-explicit-animation.md/

Lottie

https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/reference/arkui-ts/ts-components-canvas-lottie.md/

https://mp.weixin.qq.com/s/2adu8dNI9nedcNn4D4fjJw

OpenHarmony知识体系共建开发仓

https://gitee.com/openharmony-sig/knowledge/blob/master/docs/co-construct_demos/README_zh.md

OpenHarmony学习路径

https://growing.openharmony.cn/mainPlay/learnPath

小熊派BearPi-HM Nano开发板学习路径

https://growing.openharmony.cn/mainPlay/learnPathMaps?id=19

https://gitee.com/bearpi/bearpi-hm_nano/tree/master

润和DAYU200(RK3568)开发板介绍

https://growing.openharmony.cn/mainPlay/learnPathMaps?id=27

OpenHarmony有氧拳击之设备端开发

https://mp.weixin.qq.com/s/qVEFKid2gHsU34VearI7Gw

OpenHarmony有氧拳击之应用端开发的更多相关文章

  1. Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)

    本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...

  2. web移动端开发技巧与注意事项汇总

    一.meta的使用 1.<meta name="viewport" content="width=device-width,initial-scale=1.0, m ...

  3. 移动端开发viewport深入理解(转)

    一.viewport的概念   移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域,就是浏览器上用来显示网页的那部分区域,但viewport不局限于浏览器可视区域 的大小,它 ...

  4. 移动端开发概览【webview和touch事件】

    作为一个前端,而且作为一个做移动端开发的前端,那意味着你要有三头六臂,跟iOS开发哥哥一起打酱油,跟Android开发哥哥一起修bug... Android vs Ios 我在webkit内核的chr ...

  5. Twitter Bootstrap 3.0 正式发布,更好地支持移动端开发

    Twitter Bootstrap 3.0 终于正式发布了.这是一个圆滑的,直观的和强大的移动优先的前端框架,用于更快,更容易的 Web 开发.几乎一切都已经被重新设计和重建,更好的支持移动端设备. ...

  6. 在线教学、视频会议 Webus Fox(2) 服务端开发手册

    上次在<在线教学.视频会议软件 Webus Fox(1)文本.语音.视频聊天及电子白板基本用法>里介绍了软件的基本用法.本文主要介绍服务器端如何配置.开发. 1. 配置 1.1 IIS配置 ...

  7. Android 服务端开发之开发环境配置

    Android 服务端开发之开发环境配置 这里是在Eclipse的基础上安装PhpEclipse插件方法,PHPEclipse是Eclipse的 一个用于开发PHP的插件.当然也可以采用Java开发a ...

  8. 移动端开发,几个你可能不知道的CSS单位属性。

    1. rem "em" 单位是我们开发中比较常用到的,它表示以当前元素的父元素的单位大小为基准来设置当前元素的大小:“rem” 中的 “r” 代表 “root”,它表示以根(即“h ...

  9. Swift3.0服务端开发(三) Mustache页面模板与日志记录

    本篇博客主要介绍如果在Perfect工程中引入和使用Mustache页面模板与日志记录系统.Mustache页面模板类似于PHP中的smarty模板引擎或者Java中的JSTL标签.当然Mustach ...

  10. Thrift项目Server端开发流程

    Thrift项目Server端开发流程 首先,先了解工程中所有包的功能(见下图) 该图为用户中心项目的目录结构,以下依次介绍. 1.     src/main/java com.framework:该 ...

随机推荐

  1. Django之第三方平台QQ授权登录的实现

    接入指南:https://wiki.connect.qq.com/成为开发者 准备工作 成为开发者 首先要有一个开发者账号,https://connect.qq.com/ 登录后点击用户头像,修改个人 ...

  2. 浅谈 rxgo 在项目中的使用方式

    项目中使用到了 RxGo ,感觉现有的处理方式有一定的优势,当然也有一定的有劣势,遂记录下来,免得自己忘记. 本文介绍的只是 rxgo 的一种方式而已,如果你有不错的使用方式,请不吝赐教,谢谢. 对 ...

  3. Gitlab的部署

    # Gitlab sudo docker run --detach \   --hostname gitlab.example.com \   --publish 443:443 --publish ...

  4. IDEA使用与多线程

    IDEA缩写和快捷键 psvm全称public static void main sout 全称public static void main alt+enter 处理异常 s.out 自动打印s c ...

  5. vscode 切换主侧栏可见性 原Ctrl+B 我改为了 Alt+P

    vscode 切换主侧栏可见性 原Ctrl+B 我改为了 Alt+P ctrl+b 总是想不起来

  6. Navicat 通过 Http通道 连接远程 Mysql

    https://jingyan.baidu.com/article/3d69c551aa54dff0cf02d7a0.html 注意本机ip填写 localhost

  7. 简单实用算法——位图算法(BitMap)

    目录 算法原理 优点和缺点 算法实现(C#) 算法应用 参考文章 算法原理 BitMap的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素.由于采用了Bit为单位来存储数据 ...

  8. Prometheus组件构成及介绍

    Prometheus是一个开源的监控和告警工具包,其常用的组件主要包括以下几个部分: Prometheus Server 功能:Prometheus Server是Prometheus的核心组件,负责 ...

  9. stm32芯片的SPI接口调试总结之轮询模式

    一 概念 1 组成 SPI系统可直接与各个厂家生产的多种标准外围器件接口,它只需4条线:串行时钟线(SCK).主机输入/从机输出数据线(MISO).主机输出/从机输入数据线(MOSI)和低电平有效的从 ...

  10. Docker常用基础命令详解

    Docker常用基础命令详解 欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章, 关注回复「资源」, 免费领取全网最热的Java架构师学习PDF, 转载请注明出处 http://w ...