美文网首页
canvas实现彗星扫尾效果

canvas实现彗星扫尾效果

作者: secViz | 来源:发表于2018-03-07 21:15 被阅读0次

Demo源码可参考:github地址

实现的基本原理

扫尾效果的原理是在绘制新的一帧时,不是调用clearRect清理掉画布,而是用具有一定透明度的颜色去填充之前的画布。效果如下图所示:

扫尾效果.gif
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var width = canvas.width;
    var height = canvas.height;
    var angleX = 0;
    var angleY = 0;
    var range = 50;
    var centerX = width/2;
    var centerY = height/2;
    var xSpeed = 0.05;
    var ySpeed = 0.1;

    // Ball对象的实现见文章末尾
    var ball = new Ball(10);
    ball.strokeColor = 'rgba(0,0,0,0)';

    (function drawFrame() {
        window.requestAnimationFrame(drawFrame);
        // 重点!使用半透明的白色背景填充画布,从而实现想要的拖尾效果
        context.fillStyle = 'rgba(255, 255, 255, 0.4)';
        context.fillRect(0, 0, width, height);

        ball.x = centerX + Math.sin(angleX) * range;
        ball.y = centerY + Math.sin(angleY) * range;
        angleX += xSpeed;
        angleY += ySpeed;
        ball.draw(context);
    })();

单个元素的实现

上面实现方法直接覆盖了之前整个画布内容,但是很多时候我们只是想要某个元素产生这种效果,上面的方法就不能实现这种效果了,比如下图中,最终的效果只是想要攻击的点具有彗星扫尾效果。这时需要用到canvas的globalCompositeOperation属性。

   context.globalCompositeOperation = 'destination-out';
   context.fillStyle = 'rgba(0, 0, 0, 0.3)';
   context.fillRect(0, 0, width, height);
飞线扫尾.gif

sf上看到一个哥们的流星雨教程,自己跟着实现了一个,效果如下图:


流星雨.gif
// 创建一个流星雨类
function Shoot(x1, y1) {
    this.strokeColor = '#ffffff';
    this.lineWidth = 1;
    this.x1 = x1 || 0;
    this.y1 = y1 || 0;
    this.vx = 0;       //x轴上的速度
    this.vy = 0;       //y轴上的速度
}

Shoot.prototype.draw = function (context) {
    context.save();
    context.strokeStyle = this.strokeColor;
    context.lineWidth = this.lineWidth;
    context.lineCap = 'round';

    context.beginPath();
    context.moveTo(this.x1, this.y1);
    context.lineTo(this.x1 + 2, this.y1 + 2);
    context.closePath();

    if(this.lineWidth > 0) {
        context.stroke();
    }
    context.restore();
};

//  动画代码
    var canvas = document.getElementById('demo');
    var context = canvas.getContext('2d');
    var width = canvas.width;
    var height = canvas.height;

    var x = 0;
    var y = 0;
    var starNum = 100;
    var stars = [];
    var shoot;

    for(var i = 0; i < starNum; i++) {
        x = Math.random() * width;
        y = Math.random() * height;
        speed = 2;
        shoot = new Shoot(x, y);
        shoot.vx = speed;
        shoot.vy = speed;
        stars.push(shoot);
    }

    (function draw() {
        window.requestAnimationFrame(draw);
        context.save();
        context.fillStyle = "rgba(0, 0, 0, 0.8)";
        context.globalCompositeOperation = 'destination-in';
        context.fillRect(0, 0,  width, height);
        context.restore();
        stars.forEach(function (star) {
            star.x += star.vx;
            star.y += star.vy;
            star.draw(context);
        });
    })()

图像合成

globalCompositeOperation

该属性用来指定画布中的图形合成方式,可以理解为在一张画布的现有图形(原有图形)上怎么呈现另一图形(添加图形)。在上面的场景中,在每一帧中将已经存在的飞线理解为“原有图形”,将具有透明度的矩形理解为“添加图形”,我们只需要保留具有透明度的飞线,所以需要使用“destination-in”或“destination-out”


globalCompositeOperation各个值.png
globalCompositeOperation各个取值效果.png

Ball对象实现源码

function Ball(radius, color) {
    this.x = 0;
    this.y = 0;
    this.radius = radius || 40;
    this.rotation = 0;
    this.scaleX = 1;
    this.scaleY = 1;
    this.color = color || '#ff0000';
    this.strokeColor = '#000';
    this.lineWidth = 1;
    this.shadowBlur = 0;
    this.shadowColor = '#ffffff';
    //ball animation params
    this.vx = 0;       //x轴上的速度
    this.vy = 0;       //y轴上的速度
}

Ball.prototype.draw = function (context) {
    context.save();
    context.translate(this.x, this.y);
    context.rotate(this.rotation);
    context.scale(this.scaleX, this.scaleY);
    context.fillStyle = this.color;
    context.strokeStyle = this.strokeColor;
    context.lineWidth = this.lineWidth;
    context.shadowBlur = this.shadowBlur;
    context.shadowColor = this.shadowColor;
    context.beginPath();
    context.arc(0, 0, this.radius, 0, Math.PI * 2, true);
    context.fill();
    if(this.lineWidth > 0) {
        context.stroke();
    }
    context.restore();
};

参考

撩妹技能 get,教你用 canvas 画一场流星雨

相关文章

网友评论

      本文标题:canvas实现彗星扫尾效果

      本文链接:https://www.haomeiwen.com/subject/gksjfftx.html