鸿蒙系统中制作demo特效组件

描述

   

之前看到“粒子消散”的特效组件,于是就产生想法(自己也弄个特效组件应该挺有意思的)。

     

 

这个烟花特效可以添加到游戏胜利的界面中,可能还有其他应用场景哈哈。这也算是我做的第一个组件原创 demo 啦!

 

 

 

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

   

创建一个空白的工程

     

DevEco Studio 下载安装成功后,打开 DevEco Studio,点击左上角的 File,点击 New,再选择 New Project,选择 Empty Ability。

 

然后点击 Next,给项目命名 Framework,选择设备类型 Phone,选择语言类型 JS 最后点击 Finish。

 

代码删除的部分如下:

 在 entry>src>main>js>default>pages.index>index.hml 文件里把以下代码删掉:
class="title">
        {{ $t('strings.hello') }} {{ title }}
    
 

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

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

 

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

布局设计

   

 

①index.hml

 该组件是画布组件,画布的大小是整个屏幕,而按钮是显示画布上方的,所以要添加个栈组件,依次放入画布组件和按钮组件。

 

代码如下,注意这里画布组件添加了触摸事件 touchstartfunc,下文会讲解这步。

  class="stack">
        class="canvas " ref="canvas " @touchstart='touchstartfunc' >
        "button" class="STAR"  value="五角星" onclick="click_star"/>
        "button" class="TRIANGLE"  value="三角形" onclick="click_triangle"/>
        "button" class="MIX"  value="混合" onclick="click_mix"/>
    

 

②index.css

 

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

.canvas{
    width:100%;
    height100%;
    background-color:black;
}
.STAR{
    width80px;
    height38px;
    font-size20px;
    background-color:blue;
    border-color: blue;
    text-color: aquamarine;
    top:660px;
    left40px;
}
.TRIANGLE{
    width80px;
    height38px;
    font-size20px;
    background-color:blue;
    border-color: blue;
    text-color: aquamarine;
    top:660px;
    left150px;
}
.MIX{
    width80px;
    height38px;
    font-size20px;
    background-color:blue;
    border-color: blue;
    text-color: aquamarine;
    top:660px;
    left260px;
}

 

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

 

 

绘制图案

     

①五角星

 函数 draw_star 传的参数分别是烟花释放的圆心坐标,图案的颜色,图案移动的斜率,图案是否填充颜色。

 

定义的变量中,x 和 y 是图案中心的坐标,根据时间推移(会设定定时器,下文会讲)move_times 增加,图案会沿着传进来的斜率方向作直线移动,以达到烟花绽放的效果。

 

变量 a-h 都是为了便于绘制五角星的图案而设的公式参数值,全局变量 r_star 是五角星的边长,最后根据公式去绘制单个五角星图案。

 

index.js:先在 export default 上方定义变量。

var ctx;
var move_times=1;
var r_star = 5;
var r_triangle=14;   

 

 

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

 onShow() {
        ctx = this.$refs.canvas.getContext('2d');
    },

 draw_Star(x_1,y_1,color,x_2,y_2,fill) {
        let x = x_1 + move_times * x_2;
        let y = y_1 + move_times * y_2;
        let a = r_star * Math.sin(Math.PI / 10);
        let b = r_star * Math.cos(Math.PI / 10);
        let c = (r_star + a) * Math.tan(Math.PI / 10);
        let d = (r_star + a) * Math.tan(Math.PI / 5) - c;
        let e = r_star * Math.sin(Math.PI / 5);
        let f = r_star * Math.cos(Math.PI / 5);
        let g = (r_star + 2 * a) * Math.cos(2 * Math.PI / 5);
        let h = (r_star + 2 * a) * Math.sin(2 * Math.PI / 5);

        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(x - r_star - a, y - c);
        ctx.lineTo(x - a, y - c);
        ctx.lineTo(x, y - b - c);
        ctx.lineTo(x + a, y - c);
        ctx.lineTo(x + a + r_star, y - c);
        ctx.lineTo(x + a + r_star - f, y + e - c);
        ctx.lineTo(x + a + g, y + h - c);
        ctx.lineTo(x, y + d);
        ctx.lineTo(x - a - g, y + h - c);
        ctx.lineTo(x - a - r_star + f, y + e - c);
        ctx.closePath();
        ctx.stroke();
        move_times=move_times+1;
    },

 

 

②三角星

 同样, draw_triangle 是绘制单个三角形并沿设定斜率移动的函数,函数的参数类型及作用与五角星的一致。

 

全局变量 r_triangle 为三角形的边长,代码如下:

    draw_Triangle(x_1,y_1,color,x_2,y_2,fill){
        let x = x_1 + move_times * x_2;
        let y = y_1 + move_times * y_2;
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(x-r_triangle/2, y + Math.sqrt(3)*r_triangle/6);
        ctx.lineTo(x, y - Math.sqrt(3)*r_triangle/3);
        ctx.lineTo(x+r_triangle/2, y + Math.sqrt(3)*r_triangle/6);
        ctx.closePath();
        ctx.stroke();

        move_times=move_times+1;
    },

 

③图案的美化

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

 

颜色填充也是如此,1 为不填充,2 为填充,也可随机产生 1 或 2 来随机变化是否填充颜色。

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

 

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

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

 

在 ctx.stroke 下方添加代码:

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

 

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

绘制烟花

     

①烟花的布局

 绽放的烟花的形状是一个圆形,火花为单个图案。我设计了两种烟花绽放数量,一种是一个圆中有 8 个图案的,一种是一个圆中有 10 个图案的。  

它们的斜率都通过数学公式定义好了(如下的全局变量所示),单个图案沿斜率方向每次移动的距离为全局变量 R 的数值。

var R = 0.25;
var s= R*Math.cos(Math.PI/5);
var t= R*Math.sin(Math.PI/5);
var v= R*Math.cos(Math.PI/2.5);
var w= R*Math.sin(Math.PI/2.5);

 

 Draw_Star_8(click_x,click_y){
        this.draw_Star(click_x,click_y,1,-R,0,Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,2,-R/Math.sqrt(2),-R/Math.sqrt(2),Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,3,0,-R,Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,4,R/Math.sqrt(2),-R/Math.sqrt(2),Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,5,R,0,Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,6,R/Math.sqrt(2),R/Math.sqrt(2),Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,7,0,R,Math.floor(Math.random()*2 + 1));
        this.draw_Star(click_x,click_y,8,-R/Math.sqrt(2),R/Math.sqrt(2),Math.floor(Math.random()*2 + 1));
    },

    Draw_Star_10(click_x,click_y,fill){
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,0,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-s,-t,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-v,-w,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),v,-w,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),s,-t,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),R,0,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),s,t,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),v,w,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-v,w,fill);
        this.draw_Star(click_x,click_y,Math.floor(Math.random()*10 + 1),-s,t,fill);
    },

     Draw_Triangle_8(click_x,click_y,fill){
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R,             0,              fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R/Math.sqrt(2),-R/Math.sqrt(2),fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), 0,            -R,              fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R/Math.sqrt(2),-R/Math.sqrt(2),fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R,             0,              fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), R/Math.sqrt(2),R/Math.sqrt(2), fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1), 0,             R,              fill);
        this.draw_Triangle(click_x,click_y,Math.floor(Math.random()*10 + 1),-R/Math.sqrt(2),R/Math.sqrt(2), fill);
    },

    Draw_Triangle_10(click_x,click_y){
        this.draw_Triangle(click_x,click_y,1,-R,0Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,2,-s,-t,Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,3,-v,-w,Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,4,v,-w, Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,5,s,-t, Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,6,R,0,  Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,7,s,t,  Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,8,v,w,  Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,9,-v,w, Math.floor(Math.random()*2 + 1));
        this.draw_Triangle(click_x,click_y,10,-s,t,Math.floor(Math.random()*2 + 1));
    },

 

②火花的移动

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

 

代码如下:

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

 

 

然后添加定时器:

var timer_star=null;                   
var timer_triangle=null;                
var timer_mix=null;

 

 

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

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

 

 

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

鸿蒙系统

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

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

 

 

③烟花的结束

 

按上述步骤下来,会发现烟花的圆形越来越大,最终出界。为了实现烟花的结束,可以根据 movetimes 的增加次数来控制烟花绽放范围的大小。

 

通过透明度的递减,最终透明度减为 0,图案消失:

var o = 1;   

 

 

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

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

 

 

④烟花的循环绽放

 

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

  if(move_times==342){
            o=1;
            ctx.globalAlpha = o;
            move_times=1;
        };

 

 

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

run_triangle(){
        this.draw_Triangle(0,0,0,0,0,0);
        ctx.clearRect(0,0,400,800);
        this.Draw_Triangle_8(200,300,1);
        this.Draw_Triangle_8(150,200,2);
        this.Draw_Triangle_10(300,218);
        this.Draw_Triangle_10(110,380);
    },

 run_mix(){
        this.draw_Triangle(0,0,0,0,0,0);
        ctx.clearRect(0,0,400,800);
        this.Draw_Triangle_8(200,300,1);
        this.Draw_Star_10(150,200,2);
        this.Draw_Triangle_10(300,218);
        this.Draw_Star_8(110,380);
    },

 

   

点击处绽放烟花

   

 

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

var timer_click=null;
 
run_touch(){
        if(click_b2==true) {
            this.draw_Star(x, y, 000);    
            ctx.clearRect(00400800);
            this.Draw_Star_10(x, y, 1);
        }
    },

    touchstartfunc(msg) {
        click_b1==true;
        x=msg.touches[0].globalX;
        y=msg.touches[0].globalY;
        if(click_b1==true){
        timer_click=setInterval(this.run_touch,120);
            click_b1=false;
            timer_click=null;
        }
    },

 

   

烟花图案的切换

     

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

var star_b=true;                    
var mix_b=true;
var triangle_b=true;               
var click_b1=true;
var click_b2=true;

 

click_star(){
        click_b2=false;
        clearInterval(timer_triangle);
        timer_triangle=null;
        clearInterval(timer_mix);
        timer_mix=null;
        ctx.clearRect(0,0,400,800);
        if(star_b==true){
        timer_star=setInterval(this.run_star,120);
        star_b=false;
        }
        triangle_b=true;
        mix_b=true;
    },

    click_triangle(){
        click_b2=false;
        clearInterval(timer_star);
        timer_star=null;
        clearInterval(timer_mix);
        timer_mix=null;
        ctx.clearRect(0,0,400,800);
        if(triangle_b==true){
            timer_triangle=setInterval(this.run_triangle,120);
            triangle_b=false;
        }
        star_b=true;
        mix_b=true;
    },

    click_mix(){
        click_b2=false;
        clearInterval(timer_star);
        timer_star=null;
        clearInterval(timer_triangle);
        timer_triangle=null;
        ctx.clearRect(0,0,400,800);
        if(mix_b==true){
            timer_mix=setInterval(this.run_mix,120);
            mix_b=false;
        }
        star_b=true;
        triangle_b=true;
    },
     

背景音乐的添加

   

 

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

https://harmonyos.51cto.com/posts/7802

 

index.hml:

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

 

 

index.js:

var video_b =true;   

 

 

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

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

 

 

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

    onShow() {
        ctx = this.$refs.canvas.getContext('2d');
        this.$element('videoId').start();
    },

    onHide(){
    clearInterval(timer_star);
    timer_star=null;
    clearInterval(timer_triangle);
    timer_triangle=null;
    clearInterval(timer_mix);
    timer_mix=null;
    clearInterval(timer_click);
    timer_click=null;
    video_b=false;
    this.$element('videoId').pause();
    },

    onDestroy(){
        clearInterval(timer_star);
        timer_star=null;
        clearInterval(timer_triangle);
        timer_triangle=null;
        clearInterval(timer_mix);
        timer_mix=null;
        clearInterval(timer_click);
        timer_click=null;
        video_b=false;
        this.$element('videoId').pause();
    },
     

结语

   

 

以上就是我这次的小分享啦!自己的第一个 demo 开发,略微粗糙!更多资料请关注我们的项目 : Awesome-Harmony_木棉花。

https://gitee.com/hiharmonica/awesome-harmony-os-kapok

 

点击关注鸿蒙技术社区了解鸿蒙一手资讯  鸿蒙系统

求分享

鸿蒙系统

求点赞

鸿蒙系统

求在看


原文标题:我做的第一款鸿蒙demo!

文章出处:【微信公众号:HarmonyOS技术社区】欢迎添加关注!文章转载请注明出处。


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分