内容简介:流星是一种唯美的天文现象,我一度想用所学知识将它绘制,最近阅读MDN上的canvas教程得到启发,用一个canvas的长尾效果绘制流星……我们知道,canvas动画实现依赖于画布的重绘,通过不停的清空画布,绘制画布就能实现基本的动画效果。一般使用clearRect方法清除指定矩形区域,来实现重绘。长尾效果是使用透明的填充色代替clearRect方法来实现的。吐槽:由于录屏软件fps跟不上canvas所以这个gif图有点卡顿
流星是一种唯美的天文现象,我一度想用所学知识将它绘制,最近阅读MDN上的canvas教程得到启发,用一个canvas的长尾效果绘制流星……
什么是长尾效果?
我们知道,canvas动画实现依赖于画布的重绘,通过不停的清空画布,绘制画布就能实现基本的动画效果。一般使用clearRect方法清除指定矩形区域,来实现重绘。长尾效果是使用透明的填充色代替clearRect方法来实现的。
使用clearRect
吐槽:由于录屏软件fps跟不上canvas所以这个gif图有点卡顿
使用fillRect
1.透明度为1
可以看出透明度为1时,效果与清除效果一致,我们可以理解为在画布上又盖上了一画布 ,遮住了之前所画的内容所以和清除效果是一样的。
2.透明度为0
透明度为0的效果,则等价于没有清除画布的效果,此时运动的球体像一只尾巴不断变长的蛇,可以以此猜想,将透明度设为0~1之间,就能调整尾巴的长度,达到一个带尾巴的运动模糊效果。
3.长尾效果
因为不断盖上透明的画布,所以从绘制点到出发点就产生了一条颜色不断变浅的路径,给人视觉效果就是一个动态模糊。
流星
可以将流星解构为一个圆形和长尾效果:
肉眼效果:
实际效果:
封装页面形状
使用面向对象编程完成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绘制流星夜空》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- ViewGroup 默认顺序绘制子 View,如何修改?什么场景需要修改绘制顺序?
- Shader 绘制基础图形
- css绘制特殊图形
- View 绘制流程分析
- CSS图形绘制总结
- Flutter绘制弯曲虚线
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。