HarmonyOS烟花特效组件开发

开发 OpenHarmony
之前看到“粒子消散”的特效组件,于是就产生想法(自己也弄个特效组件应该挺有意思的)。这个烟花特效可以添加到游戏胜利的界面中,可能还有其他应用场景哈哈~。

[[431264]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

之前看到“粒子消散”的特效组件,于是就产生想法(自己也弄个特效组件应该挺有意思的)。这个烟花特效可以添加到游戏胜利的界面中,可能还有其他应用场景哈哈~。这也算是我做的第一个组件原创demo啦。

概述

效果图如下:

有三种模式可以选择,一种是图案只有五角星,一种是图案只有三角形,还有一种是图案既有五角星又有三角星。颜色有10种,还有背景音乐(自己DIY的烟花音效)!话不多说,开整!

正文

1.创建一个空白的工程

DevEco Studio下载安装成功后,打开DevEco Studio,点击左上角的File,点击New,再选择New Project,选择Empty Ability,然后点击Next,给项目命名Framework,选择设备类型Phone,选择语言类型JS最后点击Finish。

代码删除的部分

在entry>src>main>js>default>pages.index>index.hml 文件里把以下代码删掉

  1. <text class="title"
  2.         {{ $t('strings.hello') }} {{ title }} 
  3.     </text> 

 在entry>src>main>js>default>pages.index>index.js 文件里把以下代码删掉

  1. title:" " 
  2.    onInit() { 
  3.         this.title = this.$t('strings.world'); 
  4.     } 

 在entry>src>main>js>default>pages.index>index.css 文件里把container部分以下的代码删掉

2.布局设计

index.hml

该组件是画布组件,画布的大小是整个屏幕,而按钮是显示画布上方的,所以要添加个栈组件,依次放入画布组件和按钮组件。代码如下👇,注意这里画布组件添加了触摸事件touchstartfunc,下文会讲解这步。

  1. <stack class="stack"
  2.       <canvas class="canvas " ref="canvas " @touchstart='touchstartfunc' ></canvas> 
  3.       <input type="button" class="STAR"  value="五角星" onclick="click_star"/> 
  4.       <input type="button" class="TRIANGLE"  value="三角形" onclick="click_triangle"/> 
  5.       <input type="button" class="MIX"  value="混合" onclick="click_mix"/> 
  6.   </stack> 

index.css

给画布组件和按钮组件设置属性,代码如下👇

  1. .canvas{ 
  2.     width:100%; 
  3.     height: 100%; 
  4.     background-color:black; 
  5. .STAR{ 
  6.     width: 80px; 
  7.     height: 38px; 
  8.     font-size: 20px; 
  9.     background-color:blue; 
  10.     border-color: blue; 
  11.     text-color: aquamarine; 
  12.     top:660px; 
  13.     left: 40px; 
  14. .TRIANGLE{ 
  15.     width: 80px; 
  16.     height: 38px; 
  17.     font-size: 20px; 
  18.     background-color:blue; 
  19.     border-color: blue; 
  20.     text-color: aquamarine; 
  21.     top:660px; 
  22.     left: 150px; 
  23. .MIX{ 
  24.     width: 80px; 
  25.     height: 38px; 
  26.     font-size: 20px; 
  27.     background-color:blue; 
  28.     border-color: blue; 
  29.     text-color: aquamarine; 
  30.     top:660px; 
  31.     left: 260px; 

此时打开模拟器,你就能得到上面效果图左1图,接下来做功能实现部分。

3.绘制图案

五角星

函数 draw_star 传的参数分别是烟花释放的圆心坐标,图案的颜色,图案移动的斜率,图案是否填充颜色。定义的变量中,x和y是图案中心的坐标,根据时间推移(会设定定时器,下文会讲)move_times增加,图案会沿着传进来的斜率方向作直线移动,以达到烟花绽放的效果。变量a-h都是为了便于绘制五角星的图案而设的公式参数值,全局变量r_star是五角星的边长,最后根据公式去绘制单个五角星图案

index.js

先在export default上方定义变量

  1. var ctx; 
  2. var move_times=1; 
  3. var r_star = 5; 
  4. var r_triangle=14;      

 然后在export default下方添加代码:

  1. onShow() { 
  2.        ctx = this.$refs.canvas.getContext('2d'); 
  3.    }, 
  4.  
  5. draw_Star(x_1,y_1,color,x_2,y_2,fill) { 
  6.        let x = x_1 + move_times * x_2; 
  7.        let y = y_1 + move_times * y_2; 
  8.        let a = r_star * Math.sin(Math.PI / 10); 
  9.        let b = r_star * Math.cos(Math.PI / 10); 
  10.        let c = (r_star + a) * Math.tan(Math.PI / 10); 
  11.        let d = (r_star + a) * Math.tan(Math.PI / 5) - c; 
  12.        let e = r_star * Math.sin(Math.PI / 5); 
  13.        let f = r_star * Math.cos(Math.PI / 5); 
  14.        let g = (r_star + 2 * a) * Math.cos(2 * Math.PI / 5); 
  15.        let h = (r_star + 2 * a) * Math.sin(2 * Math.PI / 5); 
  16.  
  17.        ctx.lineWidth=1; 
  18.        ctx.beginPath(); 
  19.        ctx.moveTo(x - r_star - a, y - c); 
  20.        ctx.lineTo(x - a, y - c); 
  21.        ctx.lineTo(x, y - b - c); 
  22.        ctx.lineTo(x + a, y - c); 
  23.        ctx.lineTo(x + a + r_star, y - c); 
  24.        ctx.lineTo(x + a + r_star - f, y + e - c); 
  25.        ctx.lineTo(x + a + g, y + h - c); 
  26.        ctx.lineTo(x, y + d); 
  27.        ctx.lineTo(x - a - g, y + h - c); 
  28.        ctx.lineTo(x - a - r_star + f, y + e - c); 
  29.        ctx.closePath(); 
  30.        ctx.stroke(); 
  31.        move_times=move_times+1; 
  32.    }, 

三角星

同样, draw_triangle 是绘制单个三角形并沿设定斜率移动的函数,函数的参数类型及作用与五角星的一致。全局变量r_triangle为三角形的边长,代码如下👇

  1. draw_Triangle(x_1,y_1,color,x_2,y_2,fill){ 
  2.        let x = x_1 + move_times * x_2; 
  3.        let y = y_1 + move_times * y_2; 
  4.        ctx.lineWidth=1; 
  5.        ctx.beginPath(); 
  6.        ctx.moveTo(x-r_triangle/2, y + Math.sqrt(3)*r_triangle/6); 
  7.        ctx.lineTo(x, y - Math.sqrt(3)*r_triangle/3); 
  8.        ctx.lineTo(x+r_triangle/2, y + Math.sqrt(3)*r_triangle/6); 
  9.        ctx.closePath(); 
  10.        ctx.stroke(); 
  11.  
  12.        move_times=move_times+1; 
  13.    }, 

图案的美化

设置了10种颜色的颜色字典,通过绘制图案函数draw中的参数 color 去控制颜色(黑色是作保护作用),颜色可通过单独设置数字1-10来选择,也可以通过随机数(1~10)去随机变化颜色。颜色填充也是如此,1为不填充,2为填充,也可随机产生1或2来随机变化是否填充颜色。

  1. var drawcolors=[0,1,2,3,4,5,6,7,8,9,10]; 
  2. const COLORS={ 
  3.     "0":'black'
  4.     "1":"#FF2E10"
  5.     "2":"#FB8D15"
  6.     "3":"#F4ED1C"
  7.     "4":"#C5F31D"
  8.     "5":"#51F11F"
  9.     "6":"#18F8F8"
  10.     "7":"#1166FF"
  11.     "8":"#9833DD"
  12.     "9":"#FC14EB"
  13.     "10":"#C64A6A" 

draw函数中,在ctx.lineWidth下方,在ctx.beginPath上方添加代码:

  1. ctx.strokeStyle = COLORS[drawcolors[color].toString()]; 

 在ctx.stroke下方添加代码

  1. if(fill==2) { 
  2.             ctx.fillStyle = COLORS[drawcolors[color].toString()]; 
  3.             ctx.fill(); 
  4.         }; 

draw开头的函数是绘制单个图案,接下来的Draw函数是绘制8个或10个图案围成圆形向外同速率扩展的图像,run开头的函数是被循环的函数

4.绘制烟花

烟花的布局

绽放的烟花的形状是一个圆形,火花为单个图案。我设计了两种烟花绽放数量,一种是一个圆中有8个图案的,一种是一个圆中有10个图案的,它们的斜率都通过数学公式定义好了(如下的全局变量所示),单个图案沿斜率方向每次移动的距离为全局变量R的数值。

  1. var R = 0.25; 
  2. var s= R*Math.cos(Math.PI/5); 
  3. var t= R*Math.sin(Math.PI/5); 
  4. var v= R*Math.cos(Math.PI/2.5); 
  5. var w= R*Math.sin(Math.PI/2.5); 
  1. Draw_Star_8(click_x,click_y){ 
  2.        this.draw_Star(click_x,click_y,1,-R,0,Math.floor(Math.random()*2 + 1)); 
  3.        this.draw_Star(click_x,click_y,2,-R/Math.sqrt(2),-R/Math.sqrt(2),Math.floor(Math.random()*2 + 1)); 
  4.        this.draw_Star(click_x,click_y,3,0,-R,Math.floor(Math.random()*2 + 1)); 
  5.        this.draw_Star(click_x,click_y,4,R/Math.sqrt(2),-R/Math.sqrt(2),Math.floor(Math.random()*2 + 1)); 
  6.        this.draw_Star(click_x,click_y,5,R,0,Math.floor(Math.random()*2 + 1)); 
  7.        this.draw_Star(click_x,click_y,6,R/Math.sqrt(2),R/Math.sqrt(2),Math.floor(Math.random()*2 + 1)); 
  8.        this.draw_Star(click_x,click_y,7,0,R,Math.floor(Math.random()*2 + 1)); 
  9.        this.draw_Star(click_x,click_y,8,-R/Math.sqrt(2),R/Math.sqrt(2),Math.floor(Math.random()*2 + 1)); 
  10.    }, 
  11.  
  12.    Draw_Star_10(click_x,click_y,fill){ 
  13.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,0,fill); 
  14.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-s,-t,fill); 
  15.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-v,-w,fill); 
  16.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),v,-w,fill); 
  17.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),s,-t,fill); 
  18.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),R,0,fill); 
  19.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),s,t,fill); 
  20.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),v,w,fill); 
  21.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-v,w,fill); 
  22.        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-s,t,fill); 
  23.    }, 
  24.  
  25.     Draw_Triangle_8(click_x,click_y,fill){ 
  26.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,             0,              fill); 
  27.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R/Math.sqrt(2),-R/Math.sqrt(2),fill); 
  28.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), 0,            -R,              fill); 
  29.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R/Math.sqrt(2),-R/Math.sqrt(2),fill); 
  30.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R,             0,              fill); 
  31.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R/Math.sqrt(2),R/Math.sqrt(2), fill); 
  32.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), 0,             R,              fill); 
  33.        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R/Math.sqrt(2),R/Math.sqrt(2), fill); 
  34.    }, 
  35.  
  36.    Draw_Triangle_10(click_x,click_y){ 
  37.        this.draw_Triangle(click_x,click_y,1,-R,0, Math.floor(Math.random()*2 + 1)); 
  38.        this.draw_Triangle(click_x,click_y,2,-s,-t,Math.floor(Math.random()*2 + 1)); 
  39.        this.draw_Triangle(click_x,click_y,3,-v,-w,Math.floor(Math.random()*2 + 1)); 
  40.        this.draw_Triangle(click_x,click_y,4,v,-w, Math.floor(Math.random()*2 + 1)); 
  41.        this.draw_Triangle(click_x,click_y,5,s,-t, Math.floor(Math.random()*2 + 1)); 
  42.        this.draw_Triangle(click_x,click_y,6,R,0,  Math.floor(Math.random()*2 + 1)); 
  43.        this.draw_Triangle(click_x,click_y,7,s,t,  Math.floor(Math.random()*2 + 1)); 
  44.        this.draw_Triangle(click_x,click_y,8,v,w,  Math.floor(Math.random()*2 + 1)); 
  45.        this.draw_Triangle(click_x,click_y,9,-v,w, Math.floor(Math.random()*2 + 1)); 
  46.        this.draw_Triangle(click_x,click_y,10,-s,t,Math.floor(Math.random()*2 + 1)); 
  47.    }, 

火花的移动

上述提过一个movetimes,火花的移动无非就是坐标的变化,通过设置一个定时器,循环绘制图案就能实现移动的效果,先构造一个被循环的函数run_star(举五角星的实例,三角形同理;位置,美化等的参数随意),代码如下

  1. run_star(){ 
  2.      this.Draw_Star_10(200,300,1); 
  3.      this.Draw_Star_10(150,200,2); 
  4.      this.Draw_Star_8(300,218); 
  5.      this.Draw_Star_8(110,380); 
  6.   }, 

 然后添加定时器

  1. var timer_star=null;                    
  2. var timer_triangle=null;                 
  3. var timer_mix=null

 点击按钮“五角星”时会释放图案为五角星的烟花

  1. click_star(){ 
  2.        timer_star=setInterval(this.run_star,120); 
  3.    }, 

此时,打开模拟器,你会看到图案移动了,但上一个图案没有清除

#星光计划1.0# 【木棉花】:烟花特效组件开发-鸿蒙HarmonyOS技术社区

所以要给被循环的函数添加一个清空操作(为了保护清空函数,要先在清空前加点东西),在this.Draw函数之前添加以下代码:

  1. this.draw_Star(0,0,0,0,0,0); 
  2.   ctx.clearRect(0,0,400,800); 

烟花的结束

按上述步骤下来,会发现烟花的圆形越来越大,最终出界。

为了实现烟花的结束,可以根据movetimes的增加次数来控制烟花绽放范围的大小。通过透明度的递减,最终透明度减为0,图案消失

  1. var o = 1;    

 在draw函数里的开头位置添加以下代码:

  1. if ((move_times >= 230 && move_times <= 330)) { 
  2.           o = o - 0.01; 
  3.           ctx.globalAlpha = o; 
  4.       }; 

 烟花的循环绽放

在draw函数里的开头位置添加以下代码:

  1. if(move_times==342){ 
  2.            o=1; 
  3.            ctx.globalAlpha = o; 
  4.            move_times=1; 
  5.        }; 

 同理可以设置“三角形”和“混合”的被循环函数

  1. run_triangle(){ 
  2.         this.draw_Triangle(0,0,0,0,0,0); 
  3.         ctx.clearRect(0,0,400,800); 
  4.         this.Draw_Triangle_8(200,300,1); 
  5.         this.Draw_Triangle_8(150,200,2); 
  6.         this.Draw_Triangle_10(300,218); 
  7.         this.Draw_Triangle_10(110,380); 
  8.     }, 
  9.  
  10.  run_mix(){ 
  11.         this.draw_Triangle(0,0,0,0,0,0); 
  12.         ctx.clearRect(0,0,400,800); 
  13.         this.Draw_Triangle_8(200,300,1); 
  14.         this.Draw_Star_10(150,200,2); 
  15.         this.Draw_Triangle_10(300,218); 
  16.         this.Draw_Star_8(110,380); 
  17.     }, 

5.点击处绽放烟花

先获取点击处相对于画布组件左上角的坐标,然后作为新烟花绽放的圆心坐标传参,这里的click_b1,click_b2下文会讲解

  1. var timer_click=null
  1. run_touch(){ 
  2.         if(click_b2==true) { 
  3.             this.draw_Star(x, y, 0, 0, 0);     
  4.             ctx.clearRect(0, 0, 400, 800); 
  5.             this.Draw_Star_10(x, y, 1); 
  6.         } 
  7.     }, 
  8.  
  9.     touchstartfunc(msg) { 
  10.         click_b1==true
  11.         x=msg.touches[0].globalX; 
  12.         y=msg.touches[0].globalY; 
  13.         if(click_b1==true){ 
  14.         timer_click=setInterval(this.run_touch,120); 
  15.             click_b1=false
  16.             timer_click=null
  17.         } 
  18.     }, 

6.烟花图案的切换

通过设定布尔型变量来控制点击另一个按钮时,清空上一个按钮运行的定时器。

  1. var star_b=true;                     
  2. var mix_b=true
  3. var triangle_b=true;                
  4. var click_b1=true
  5. var click_b2=true
  1. click_star(){ 
  2.         click_b2=false
  3.         clearInterval(timer_triangle); 
  4.         timer_triangle=null
  5.         clearInterval(timer_mix); 
  6.         timer_mix=null
  7.         ctx.clearRect(0,0,400,800); 
  8.         if(star_b==true){ 
  9.         timer_star=setInterval(this.run_star,120); 
  10.         star_b=false
  11.         } 
  12.         triangle_b=true
  13.         mix_b=true
  14.     }, 
  15.  
  16.     click_triangle(){ 
  17.         click_b2=false
  18.         clearInterval(timer_star); 
  19.         timer_star=null
  20.         clearInterval(timer_mix); 
  21.         timer_mix=null
  22.         ctx.clearRect(0,0,400,800); 
  23.         if(triangle_b==true){ 
  24.             timer_triangle=setInterval(this.run_triangle,120); 
  25.             triangle_b=false
  26.         } 
  27.         star_b=true
  28.         mix_b=true
  29.     }, 
  30.  
  31.     click_mix(){ 
  32.         click_b2=false
  33.         clearInterval(timer_star); 
  34.         timer_star=null
  35.         clearInterval(timer_triangle); 
  36.         timer_triangle=null
  37.         ctx.clearRect(0,0,400,800); 
  38.         if(mix_b==true){ 
  39.             timer_mix=setInterval(this.run_mix,120); 
  40.             mix_b=false
  41.         } 
  42.         star_b=true
  43.         triangle_b=true
  44.     }, 

7.背景音乐的添加

js模板中添加音频可以去看我之前的文章

index.hml

  1. <video id='videoId' 
  2.          src='/common/flr_5_1.mp3' 
  3.          autoplay='true' 
  4.          controls="false" 
  5.          onfinish='finishCallback'></video> 

index.js

  1. var video_b =true;    

在src/common/下加入音频文件。

  1. finishCallback:function(){ 
  2.        if(video_b==true){ 
  3.            this.$element('videoId').start(); 
  4.        } 
  5.    }, 

别忘了生命周期的设置,在应用启动时自动播放音频,在应用隐藏的时候暂停播放音频并清空所有定时器,在应用销毁时清空所有定时器,停止播放音频。

  1. onShow() { 
  2.      ctx = this.$refs.canvas.getContext('2d'); 
  3.      this.$element('videoId').start(); 
  4.  }, 
  5.  
  6.  onHide(){ 
  7.  clearInterval(timer_star); 
  8.  timer_star=null
  9.  clearInterval(timer_triangle); 
  10.  timer_triangle=null
  11.  clearInterval(timer_mix); 
  12.  timer_mix=null
  13.  clearInterval(timer_click); 
  14.  timer_click=null
  15.  video_b=false
  16.  this.$element('videoId').pause(); 
  17.  }, 
  18.  
  19.  onDestroy(){ 
  20.      clearInterval(timer_star); 
  21.      timer_star=null
  22.      clearInterval(timer_triangle); 
  23.      timer_triangle=null
  24.      clearInterval(timer_mix); 
  25.      timer_mix=null
  26.      clearInterval(timer_click); 
  27.      timer_click=null
  28.      video_b=false
  29.      this.$element('videoId').pause(); 
  30.  }, 

结语

以上就是我这次的小分享啦❀❀!自己的第一个demo开发,略微粗糙。

文章相关附件可以点击下面的原文链接前往下载:

https://harmonyos.51cto.com/resource/1376

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

【编辑推荐】

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2016-09-19 21:37:58

vue特效组件Web

2021-08-12 14:59:15

鸿蒙HarmonyOS应用

2021-06-22 09:44:56

鸿蒙HarmonyOS应用

2022-09-14 15:17:26

ArkUI鸿蒙

2021-03-30 09:45:07

鸿蒙HarmonyOS应用开发

2021-03-17 09:35:09

鸿蒙HarmonyOS应用开发

2021-03-26 09:35:35

鸿蒙HarmonyOS应用开发

2022-05-19 15:59:23

组件焦点鸿蒙

2021-03-31 15:49:34

鸿蒙HarmonyOS应用

2021-11-01 10:21:36

鸿蒙HarmonyOS应用

2021-01-18 09:52:20

鸿蒙HarmonyOS开发

2021-05-12 15:17:39

鸿蒙HarmonyOS应用

2021-02-04 09:45:19

鸿蒙HarmonyOS应用开发

2021-06-28 14:48:03

鸿蒙HarmonyOS应用

2022-04-24 15:17:56

鸿蒙操作系统

2022-07-06 20:24:08

ArkUI计时组件

2021-01-12 12:04:40

鸿蒙HarmonyOS应用开发

2021-01-11 11:36:23

鸿蒙HarmonyOSApp开发

2021-01-21 13:21:18

鸿蒙HarmonyOSPhotoview组件

2021-01-20 09:54:56

鸿蒙HarmonyOS开发
点赞
收藏

51CTO技术栈公众号