0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何使用属性动画实现简单属性变化的动画效果

OpenAtom OpenHarmony 来源:OpenAtom OpenHarmony 作者:OpenAtom OpenHarmony 2022-09-29 09:44 次阅读

一、简介

继《OpenHarmony有氧拳击设备端的开发》后,本次为大家带来酷炫的应用端开发。如下视频,开发者伴随着音乐,律动出拳后,那开发板屡屡播放“挨打”效果,这究竟是怎么一回事?让我们一探背后原理。 这款拳击游戏开始时会播放音乐,然后以随机速度下落“击拳方块”。当小哥哥在击拳区域内挥拳时,游戏会判断方块的位置,根据不同位置确定播放普通击中或完美击中的动画效果。

5f75193c-3f2f-11ed-9e49-dac502259ad0.png

二、动画

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

三、“下落”动画

5fc85f84-3f2f-11ed-9e49-dac502259ad0.gif

1、属性动画介绍

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

AnimationOptions对象说明

● 属性

62f4e4ca-3f2f-11ed-9e49-dac502259ad0.png

接口

6316b8a2-3f2f-11ed-9e49-dac502259ad0.png

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)            // .....}

632fd616-3f2f-11ed-9e49-dac502259ad0.gif

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()}

6488174e-3f2f-11ed-9e49-dac502259ad0.gif

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{            // 未抵达区域        }    }

四、击中动画

64fc4326-3f2f-11ed-9e49-dac502259ad0.gif

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

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,如下:

importlottiefrom'@ohos/lottieETS'

放置动画资源

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

69910728-3f2f-11ed-9e49-dac502259ad0.png

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的开发,更加完善样例,相互学习,相互进步。

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 定时器
    +关注

    关注

    23

    文章

    3144

    浏览量

    112006
  • 动画
    +关注

    关注

    0

    文章

    20

    浏览量

    8389
  • OpenHarmony
    +关注

    关注

    23

    文章

    3214

    浏览量

    15153

原文标题:OpenHarmony有氧拳击之应用端开发

文章出处:【微信号:gh_e4f28cfa3159,微信公众号:OpenAtom OpenHarmony】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    LabVIEW中动画实现的一种新方法

    期更新控件的“Position”属性实现;合理编辑刀具控件Ture和False状态的图形,再将控件状态作周期交替变化,可实现刀具转动效果
    发表于 01-08 11:30

    荣小菜补钙记第14期:给界面添加“飞入”动画效果

    都很熟悉PPT的动画效果“飞入”了,很明显,比起生硬的换页,在切换时增加一些额外的动画效果可以极大提升用户体验。2.Demo1介绍Demo1演示如下,原理比较
    发表于 02-28 13:30

    Scratch实现一个按钮的动画效果

    上次介绍了利用克隆体操作生成菜单按钮,今天讲一讲如何让一个按钮具有动画效果:当鼠标移到某个按钮上面时,显示动画效果让菜单按钮有虚像效果让菜
    发表于 06-29 08:51

    模仿手机充电中电量自动过渡的动画

    完成的页面图:模仿手机充电中电量自动过渡的动画;绿色部分水平方向匀速增加,并循环动画;闪电标志也不停在闪烁。经典代码:图1 图2 Animation(动画)复合属性: one 5s l
    发表于 12-29 07:50

    HarmonyOS Lottie组件,让动画绘制更简单

    能力帮助开发者美化了UI界面,但不适用于绘制某些比较复杂的动画,例如,属性动画主要针对动画的通用属性进行动态
    发表于 02-22 14:55

    基于HarmonyOS实现的电池充电动画效果

    ;/option&gt;&lt;/select&gt;最终的效果总结这些还只是鸿蒙组件库中动画样式里的一小部分,如果再使用旋转加平移属性就能实现更加炫酷的
    发表于 03-28 12:02

    OpenHarmony有氧拳击之应用端开发

    ; }五、总结本文主要讲述了拳击互动游戏中,如何使用属性动画实现简单属性变化
    发表于 10-09 15:19

    如何使用lvgl定时器实现动画效果

    在LVGL中,如何使用lvgl定时器实现动画效果
    发表于 12-15 15:23

    HarmonyOS/OpenHarmony应用开发-属性动画

    组件的某些通用属性变化时,可以通过属性动画实现渐变过渡效果,提升用户体验。支持的
    发表于 01-03 10:51

    HarmonyOS属性动画开发示例(ArkTS)

    介绍 利用 ArkUI 组件不仅可以实现属性变化引起的属性动画,也可以实现父组件状态
    发表于 11-23 15:31

    根据tableView的特点,操作Cell实现一些动画效果

    一些动画效果。 我写了一个简单动画集 TableViewAnimationKit,只需要一行代码就可以让tableView实现
    发表于 09-25 09:30 0次下载
    根据tableView的特点,操作Cell<b class='flag-5'>实现</b>一些<b class='flag-5'>动画</b><b class='flag-5'>效果</b>

    动画激光灯的特点_动画激光灯应用

    动画激光灯是一种能跟随播放的音乐节奏能打出各种文字和图案的设备。它不仅内设红黄绿三种颜色的激光动画来搭配舞台效果而且还能实现旋转、缩放、频闪、三维
    发表于 04-09 17:25 1505次阅读

    QML中的动画设计,太“难”了

    alwaysRunToEnd:该属性接收布尔类型的参数。该属性保存动画是否运行到完成才停止。当loops属性被设置时,这个属性是最有用的,因
    的头像 发表于 09-09 10:16 1239次阅读

    在QML动画设计中通过指定关键帧创建时间线动画

    在QML动画设计中,可以通过指定关键帧创建时间线动画;还可以将时间线绑定到组件(如滑块)的属性值,以这种方式控制动画
    的头像 发表于 10-10 11:27 1416次阅读

    鸿蒙开发之发动画

    FPS(Frame Per Second),即每秒的动画帧数,帧率越高则动画就会越流畅。 ArkUI中,产生动画的方式是改变属性值且指定动画
    的头像 发表于 02-01 15:25 167次阅读
    鸿蒙开发之发<b class='flag-5'>动画</b>篇