还在用canvas画格子吗?文字烟花效果更不错噢

2,517 阅读4分钟

💞“在人间贩卖声音 等凑够满天星辰 放烟花给你看

gif4

上次的烟花有些许平淡,这次来放大招了,让你的名字在天空绽放!

喜欢的话可以私信源码去晒狗粮噢~

全程高能,无尿点,有部分内容在上期的文章中噢~

实现效果

name

你以为仅此而已吗,后面还有大招噢

实现过程

1. 在画布上绘制文字

通过ctx.font设定字体的大小以及字体,再填充颜色,最后通过ctx.fillText绘制到画布当中,这里有几个需要注意的地方:

注意

  1. ctx.font至少需要两个参数,一个字体大小,一个字体
  2. 这里的颜色之所以设为#000001原因是背景是黑色的,这样这个字不会被看到,但是它是真实存在的,不然每次点击时都会有一个字体生成在左上角,影响视觉,当然也可以新建在一个画布,这里就简单处理了
  3. ctx.measureText(text):返回一个对象,该对象包含以像素计的指定字体宽度
// 填充字体样式
let font = 120
ctx.font = font + "px '微软雅黑'"
ctx.fillStyle = "#000001"
// 内容
let text = '小丞同学'
// 获取字体的宽度
let textWidth = ctx.measureText(text).width
// 在左上角填充字体
ctx.fillText(text,0 , font)

2. 获取像素点

通过ctx.getImageData可以获取一个区域内的像素数据,返回的是一个imageData对象

对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:

  • R - 红色 (0-255)
  • G - 绿色 (0-255)
  • B - 蓝色 (0-255)
  • A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)

在前面的代码中我们在 (0,0) 的位置绘制了字体,我们通过getImageData将这块区域的像素信息取出来。

let imgData = ctx.getImageData(0, 0, textWidth, font * 1.2)

我们先看看imgData,可以看到里面的数据十分庞大,里面存储的是像素信息

对象

这样我们可以通过判断这些像素点来实现粒子的效果

3. 实现文字粒子化

在上面一步中我们已经将文字的像素信息得到了,也就相当于我们复制了一个文字,我们可以遍历整个imgData.data数组就能绘制出原先的文字,那我们要实现粒子化的效果,就需要隔几个像素格再绘制,这样绘制处理的图形就会是一个粒子化的效果,原因就是部分位置的像素,没有进行渲染

for (let h = 0; h < font * 1.2; h += 6) {
    for (let w = 0; w < textWidth; w += 6) {
        let position = (textWidth * h + w) * 4;
        // 返回的数组是rgba的方式存储
        let r = imgData.data[position],
            g = imgData.data[position + 1],
            b = imgData.data[position + 2],
            a = imgData.data[position + 3];
        if (r + g + b == 0) {
            continue
        }
        //烟花代码
    }
}

在上面的代码块中,遍历了从左到右,从上到下,遍历了整个图形区域的全部像素信息,r,g,b,a对应一个某个像素点的颜色,当颜色不为黑色时,我们不对它进行操作,跳过此轮循环,当颜色不为黑色时,利用该点的信息生成一个烟花粒子

image-20210621165731907

let firework = {};
firework.x = x;
firework.y = y;
firework.fx = x + w - textWidth / 2;
firework.fy = y + h - font / 2;
firework.size = Math.floor(Math.random() * 2) + 1;
firework.speed = 1;
setColors(firework);
fireworks.push(firework);

烟花粒子对象存入烟花数组中

4. 设置粒子动画

现在我们已经得到了一整个即将绽放的烟花数组,我们只需要给他们加上动画,通过每次渲染时改变当前粒子的坐标,降低透明度实现烟花殆尽的效果,直至烟花粒子透明度降为0

关键代码

firework.x += (firework.fx - firework.x) / 10;
firework.y += (firework.fy - firework.y) / 10 - (firework.alpha - 1) * firework.speed;
firework.alpha -= 0.01;
// 如果透明度小于0就删除这个粒子
if (firework.alpha <= 0) {
    fireworks.splice(i, 1);
    // 跳过这次循环,不进行绘制
    continue;
}

5. 设置拖尾并渲染更新画布

拖尾实现的思路是不断的添加一个半透明的蒙层来实现,使用 requestAnimationFrame于定时器的区别在上篇文章有讲过噢

function tick() {
    // // 设置拖影
    ctx.globalCompositeOperation = 'destination-out';
    ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = 'lighter';
    // 更新画布
    drawFires();
    requestAnimationFrame(tick);
}

总结

今天的烟花就到这里反映结束了,不过瘾的话,可以让我们一起期待下一篇图片烟花效果噢~摩尔庄园的烟花也很好看噢!

name