一、簡介
繼《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,如下:
importlottiefrom'@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的開發,更加完善樣例,相互學習,相互進步。
-
定時器
+關注
關注
23文章
3256瀏覽量
115442 -
動畫
+關注
關注
0文章
20瀏覽量
8558 -
OpenHarmony
+關注
關注
25文章
3749瀏覽量
16660
原文標題:OpenHarmony有氧拳擊之應用端開發
文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論