[文章]【木棉花】:烟花特效组件开发

阅读量0
0
0


前言
之前看到“粒子消散”的特效组件,于是就产生想法(自己也弄个特效组件应该挺有意思的)。这个烟花特效可以添加到游戏胜利的界面中,可能还有其他应用场景哈哈~。这也算是我做的第一个组件原创demo啦,欢迎各位评论区指导一下O(∩_∩)O
概述
效果图如下
3.gif

有三种模式可以选择,一种是图案只有五角星,一种是图案只有三角形,还有一种是图案既有五角星又有三角星。颜色有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="五角星"/>
  4.         <input type="button" class="TRIANGLE"  value="三角形"/>
  5.         <input type="button" class="MIX"  value="混合"/>
  6.     </stack>

复制代码

index.css给画布组件和按钮组件设置属性,代码如下
  1. .canvas{
  2.     width:100%;
  3.     height: 100%;
  4.     background-color:black;
  5. }
  6. .STAR{
  7.     width: 80px;
  8.     height: 38px;
  9.     font-size: 20px;
  10.     background-color:blue;
  11.     border-color: blue;
  12.     text-color: aquamarine;
  13.     top:660px;
  14.     left: 40px;
  15. }
  16. .TRIANGLE{
  17.     width: 80px;
  18.     height: 38px;
  19.     font-size: 20px;
  20.     background-color:blue;
  21.     border-color: blue;
  22.     text-color: aquamarine;
  23.     top:660px;
  24.     left: 150px;
  25. }
  26. .MIX{
  27.     width: 80px;
  28.     height: 38px;
  29.     font-size: 20px;
  30.     background-color:blue;
  31.     border-color: blue;
  32.     text-color: aquamarine;
  33.     top:660px;
  34.     left: 260px;
  35. }
复制代码
此时打开模拟器,你就能得到上面效果图左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. draw_Star(x_1,y_1,color,x_2,y_2,fill) {
  5.         let x = x_1 + move_times * x_2;
  6.         let y = y_1 + move_times * y_2;
  7.         let a = r_star * Math.sin(Math.PI / 10);
  8.         let b = r_star * Math.cos(Math.PI / 10);
  9.         let c = (r_star + a) * Math.tan(Math.PI / 10);
  10.         let d = (r_star + a) * Math.tan(Math.PI / 5) - c;
  11.         let e = r_star * Math.sin(Math.PI / 5);
  12.         let f = r_star * Math.cos(Math.PI / 5);
  13.         let g = (r_star + 2 * a) * Math.cos(2 * Math.PI / 5);
  14.         let h = (r_star + 2 * a) * Math.sin(2 * Math.PI / 5);

  15.         ctx.lineWidth=1;
  16.         ctx.beginPath();
  17.         ctx.moveTo(x - r_star - a, y - c);
  18.         ctx.lineTo(x - a, y - c);
  19.         ctx.lineTo(x, y - b - c);
  20.         ctx.lineTo(x + a, y - c);
  21.         ctx.lineTo(x + a + r_star, y - c);
  22.         ctx.lineTo(x + a + r_star - f, y + e - c);
  23.         ctx.lineTo(x + a + g, y + h - c);
  24.         ctx.lineTo(x, y + d);
  25.         ctx.lineTo(x - a - g, y + h - c);
  26.         ctx.lineTo(x - a - r_star + f, y + e - c);
  27.         ctx.closePath();
  28.         ctx.stroke();
  29.         move_times=move_times+1;
  30.     },
复制代码
三角星
同样, 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.         move_times=move_times+1;
  12.     },
复制代码
图案的美化
设置了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"
  14. }
复制代码
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.     Draw_Star_10(click_x,click_y,fill){
  12.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,0,fill);
  13.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-s,-t,fill);
  14.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-v,-w,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),s,-t,fill);
  17.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),R,0,fill);
  18.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),s,t,fill);
  19.         this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),v,w,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),-s,t,fill);
  22.     },

  23.      Draw_Triangle_8(click_x,click_y,fill){
  24.         this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,             0,              fill);
  25.         this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R/Math.sqrt(2),-R/Math.sqrt(2),fill);
  26.         this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), 0,            -R,              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), R,             0,              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), 0,             R,              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.     },

  33.     Draw_Triangle_10(click_x,click_y){
  34.         this.draw_Triangle(click_x,click_y,1,-R,0, Math.floor(Math.random()*2 + 1));
  35.         this.draw_Triangle(click_x,click_y,2,-s,-t,Math.floor(Math.random()*2 + 1));
  36.         this.draw_Triangle(click_x,click_y,3,-v,-w,Math.floor(Math.random()*2 + 1));
  37.         this.draw_Triangle(click_x,click_y,4,v,-w, Math.floor(Math.random()*2 + 1));
  38.         this.draw_Triangle(click_x,click_y,5,s,-t, Math.floor(Math.random()*2 + 1));
  39.         this.draw_Triangle(click_x,click_y,6,R,0,  Math.floor(Math.random()*2 + 1));
  40.         this.draw_Triangle(click_x,click_y,7,s,t,  Math.floor(Math.random()*2 + 1));
  41.         this.draw_Triangle(click_x,click_y,8,v,w,  Math.floor(Math.random()*2 + 1));
  42.         this.draw_Triangle(click_x,click_y,9,-v,w, Math.floor(Math.random()*2 + 1));
  43.         this.draw_Triangle(click_x,click_y,10,-s,t,Math.floor(Math.random()*2 + 1));
  44.     },
复制代码
火花的移动
上述提过一个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.     },
复制代码
此时,打开模拟器,你会看到图案移动了,但上一个图案没有清除,所以要给被循环的函数添加一个清空操作(为了保护清空函数,要先在清空前加点东西),在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. run_mix(){
  10.         this.draw_Triangle(0,0,0,0,0,0);
  11.         ctx.clearRect(0,0,400,800);
  12.         this.Draw_Triangle_8(200,300,1);
  13.         this.Draw_Star_10(150,200,2);
  14.         this.Draw_Triangle_10(300,218);
  15.         this.Draw_Star_8(110,380);
  16.     },
复制代码
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.     touchstartfunc(msg) {
  9.         click_b1==true;
  10.         x=msg.touches[0].globalX;
  11.         y=msg.touches[0].globalY;
  12.         if(click_b1==true){
  13.         timer_click=setInterval(this.run_touch,120);
  14.             click_b1=false;
  15.             timer_click=null;
  16.         }
  17.     },
复制代码
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.     click_triangle(){
  16.         click_b2=false;
  17.         clearInterval(timer_star);
  18.         timer_star=null;
  19.         clearInterval(timer_mix);
  20.         timer_mix=null;
  21.         ctx.clearRect(0,0,400,800);
  22.         if(triangle_b==true){
  23.             timer_triangle=setInterval(this.run_triangle,120);
  24.             triangle_b=false;
  25.         }
  26.         star_b=true;
  27.         mix_b=true;
  28.     },

  29.     click_mix(){
  30.         click_b2=false;
  31.         clearInterval(timer_star);
  32.         timer_star=null;
  33.         clearInterval(timer_triangle);
  34.         timer_triangle=null;
  35.         ctx.clearRect(0,0,400,800);
  36.         if(mix_b==true){
  37.             timer_mix=setInterval(this.run_mix,120);
  38.             mix_b=false;
  39.         }
  40.         star_b=true;
  41.         triangle_b=true;
  42.     },
复制代码
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;   
复制代码
  1.    finishCallback:function(){
  2.         if(video_b==true){
  3.             this.$element('videoId').start();
  4.         }
  5.     },
复制代码
在src/common/下加入音频文件

别忘了生命周期的设置,在应用启动时自动播放音频,在应用隐藏的时候暂停播放音频并清空所有定时器,在应用销毁时清空所有定时器,停止播放音频。
  1.     onShow() {
  2.         ctx = this.$refs.canvas.getContext('2d');
  3.         this.$element('videoId').start();
  4.     },

  5.     onHide(){
  6.     clearInterval(timer_star);
  7.     timer_star=null;
  8.     clearInterval(timer_triangle);
  9.     timer_triangle=null;
  10.     clearInterval(timer_mix);
  11.     timer_mix=null;
  12.     clearInterval(timer_click);
  13.     timer_click=null;
  14.     video_b=false;
  15.     this.$element('videoId').pause();
  16.     },

  17.     onDestroy(){
  18.         clearInterval(timer_star);
  19.         timer_star=null;
  20.         clearInterval(timer_triangle);
  21.         timer_triangle=null;
  22.         clearInterval(timer_mix);
  23.         timer_mix=null;
  24.         clearInterval(timer_click);
  25.         timer_click=null;
  26.         video_b=false;
  27.         this.$element('videoId').pause();
  28.     },
复制代码
结语
以上就是我这次的小分享啦❀❀!自己的第一个demo开发,略微粗糙,欢迎各位评论区指导一下O(∩_∩)O
更多资料请关注我们的项目 :Awesome-Harmony_木棉花

回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友