用canvas绘制流星夜空

栏目: Html5 · 发布时间: 5年前

内容简介:流星是一种唯美的天文现象,我一度想用所学知识将它绘制,最近阅读MDN上的canvas教程得到启发,用一个canvas的长尾效果绘制流星……我们知道,canvas动画实现依赖于画布的重绘,通过不停的清空画布,绘制画布就能实现基本的动画效果。一般使用clearRect方法清除指定矩形区域,来实现重绘。长尾效果是使用透明的填充色代替clearRect方法来实现的。吐槽:由于录屏软件fps跟不上canvas所以这个gif图有点卡顿

流星是一种唯美的天文现象,我一度想用所学知识将它绘制,最近阅读MDN上的canvas教程得到启发,用一个canvas的长尾效果绘制流星……

用canvas绘制流星夜空

什么是长尾效果?

我们知道,canvas动画实现依赖于画布的重绘,通过不停的清空画布,绘制画布就能实现基本的动画效果。一般使用clearRect方法清除指定矩形区域,来实现重绘。长尾效果是使用透明的填充色代替clearRect方法来实现的。

使用clearRect

吐槽:由于录屏软件fps跟不上canvas所以这个gif图有点卡顿

用canvas绘制流星夜空

使用fillRect

1.透明度为1

用canvas绘制流星夜空

可以看出透明度为1时,效果与清除效果一致,我们可以理解为在画布上又盖上了一画布 ,遮住了之前所画的内容所以和清除效果是一样的。

2.透明度为0

用canvas绘制流星夜空

透明度为0的效果,则等价于没有清除画布的效果,此时运动的球体像一只尾巴不断变长的蛇,可以以此猜想,将透明度设为0~1之间,就能调整尾巴的长度,达到一个带尾巴的运动模糊效果。

3.长尾效果

用canvas绘制流星夜空

因为不断盖上透明的画布,所以从绘制点到出发点就产生了一条颜色不断变浅的路径,给人视觉效果就是一个动态模糊。

流星

可以将流星解构为一个圆形和长尾效果:

肉眼效果:

用canvas绘制流星夜空

实际效果:

用canvas绘制流星夜空

封装页面形状

使用面向对象编程完成canvas绘制

月亮类

class Moon {
    constructor(x, y, ctx, r = 25) {
        this.x = x;
        this.y = y;
        this.ctx = ctx;
        this.r = r;
    }
    draw() {
        this.ctx.fillStyle = 'rgba(255,255,255,0.6)';
        this.ctx.shadowBlur = this.r + 5; //光晕半径
        this.ctx.shadowColor = "#fff"; // 光晕颜色
        this.ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        this.ctx.fill();
    }
}
复制代码

因为月亮是静止在页面上的,所以只有一个draw方法,月亮光晕的实现是把阴影和填充设为同一颜色,然后让阴影透明度大于填充透明度,就形成一个外发光的效果。

星星类

class Star extends Moon {
    constructor(x, y, ctx, r) {
        super(x, y, ctx, r);
    }
    draw() {
        this.ctx.fillStyle = 'rgba(255,255,255,0.8)';
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
        this.ctx.closePath();
        this.ctx.fill();
    }
    move() {
        this.x += 0.08;
        if (this.x > meteorCanvas.width) {
            this.x = 0;
        }
        this.draw();
    }
}
复制代码

星星与月亮的唯一区别是可以移动,所以用星星类去继承月亮类,实现面向对象的继承与多态。

用星星缓慢的向右移动可以模拟地球自转带来的效果。

流星类

class Meteor extends Star {
    constructor(x, y, ctx, r,angle) {
        super(x, y, ctx, r);
        this.angle = angle;
    }
    draw() {
        this.ctx.fillStyle = '#ffffff';
        this.ctx.rotate(this.angle);
        this.ctx.translate(100, -meteorCanvas.height / 1.5);
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
        this.ctx.closePath();
        this.ctx.fill();
        this.ctx.translate(-100, meteorCanvas.height / 1.5);
        this.ctx.rotate(-this.angle);
    }
    move() {
        this.x += 4;
        this.y += 1;
        if (this.x > meteorCanvas.width) {
            this.x = Math.random() * 5
            this.y = -2 * meteorCanvas.height + Math.random() * meteorCanvas.height * 3;
        }
        this.draw();
    }
}
复制代码

同理用流星类去继承星星类。

注意的是,流星类与星星类运动的不同之处是流星划过天空有一个夹角,所以在绘制时将画布旋转了角度之后,需要回归原位。

为了让流星出现的位置不会太密集,我将流星在y轴出现的位置设置在-2倍画布高度到1倍画布高度之间,并在draw方法中将画布往上挪了画布高度的2/3(同理要将画布归位)。

绘制canvas

流星需要使用长尾效果渲染,星星需要clearRect重绘,月亮就只需要绘制一次。为了三种形状互不干扰,我分别使用了不同画布去渲染它们。

优点:互不干扰,绘制逻辑清晰,优化渲染。

源码

const meteorCanvas = document.getElementById('meteor');
        const starCanvas = document.getElementById('star');
        const moonCanvas = document.getElementById('moon');
        const meteors = [], stars = [];

        meteorCanvas.width = document.body.clientWidth;
        meteorCanvas.height = document.body.clientHeight;
        starCanvas.width = document.body.clientWidth;
        starCanvas.height = document.body.clientHeight / 3;
        moonCanvas.width = document.body.clientWidth;
        moonCanvas.height = document.body.clientHeight / 3;
        const meteorCtx = meteorCanvas.getContext('2d');
        const starCtx = starCanvas.getContext('2d');
        const moonCtx = moonCanvas.getContext('2d');

        init();
        animate();

        function init() {
            for (var i = 0; i < 4; i++) {
                meteors[i] = new Meteor(Math.random() * meteorCanvas.width,
                    -2 * meteorCanvas.height + Math.random() * meteorCanvas.height * 3,
                    meteorCtx, Math.floor(Math.random() * 2) + 1.5, Math.PI / 7);
                meteors[i].draw();
            }
            for (var i = 0; i < 60; i++) {
                stars[i] = new Star(Math.random() * starCanvas.width, Math.random() * starCanvas.height,
                    starCtx, Math.random());
                stars[i].draw();
            }
            moon = new Moon(moonCanvas.width - 50, 50, moonCtx)
            moon.draw();
        }
        function animate() {
            starCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);
            meteorCtx.fillStyle = `rgba(0, 0, 0, 0.1)`;
            meteorCtx.fillRect(0, 0, meteorCanvas.width, meteorCanvas.height);
            for (let meteor of meteors)
                meteor.move();
            for (let star of stars)
                star.move();
            requestAnimationFrame(animate);
        }
        function recover() {
            for (let meteor of meteors)
                meteor = null;
            for (let star of stars)
                star = null;
            moon = null;
        }
        window.onresize = function () {
            meteorCanvas.width = document.body.clientWidth;
            meteorCanvas.height = document.body.clientHeight;
            starCanvas.width = document.body.clientWidth;
            starCanvas.height = document.body.clientHeight / 3;
            moonCanvas.width = document.body.clientWidth;
            moonCanvas.height = document.body.clientHeight / 3;
            recover();
            init();
        }
复制代码

结语

陪你去看流星雨落在这地球上

让你的泪落在我肩膀

要你相信我的爱只肯为你勇敢……

文章随着《流星雨》的歌声,也走向了尾声。人生如流星划过,转瞬即逝,然而,流星易逝,真情永恒……


以上所述就是小编给大家介绍的《用canvas绘制流星夜空》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

互联网浪尖上的女性

互联网浪尖上的女性

田玉翠 / 人民出版社 / 2017-1 / 68.00

二十三个真实、前沿的女性创业者实例,带你走进“她世界”洞悉“她经济”。《互联网浪尖上的女性》不仅仅关于创业,更是关于女性如何追逐自己的梦想,让人生更丰满、更精彩。一起来看看 《互联网浪尖上的女性》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具