本文介绍: 很久没有写关于canvas效果文章了,刚好最近又学到了一个新的特效使用canvas绘制多层次动态星空背景今天分享大家。首先我们依旧来看一下最终实现效果如图所示:由于录制GIF造成失帧,因此图片可能看不出完整动画完整的效果及代码可以拉到文章底部来进行观赏。在上图中可以简单的看出有层次的星空图在不断的变换一会儿向右移动,一会儿又向左移动最后还会进行旋转,那么这样的效果是如何实现的呢?咱们就一起来学习一下吧!

介绍

很久没有写关于 canvas 效果的文章了,刚好最近又学到了一个新的特效使用 canvas 绘制多层次动态星空背景今天就分享给大家。首先我们依旧来看一下最终实现的效果,如图所示

由于录制 GIF 造成失帧,因此图片可能看不出完整动画完整的效果及代码可以拉到文章最底部来进行观赏。

在上图中可以简单的看出有层次的星空图在不断的变换,一会儿向右移动,一会儿又向左移动最后还会进行旋转,那么这样的效果是如何实现的呢?咱们就一起来学习一下吧!

绘制动态星空

因为这个效果是使用 canvas实现的,因此咱们就需要做一些基础的准备工作,由于这次是做背景效果,因此不需要html添加默认标签我们通过代码动态插入 canvas 标签

首先还是需要准备好相关css 样式代码,涉及到的样式简单如下所示

*{margin: 0; padding: 0;
}
body {background: #000; overflow: hidden;
} 

简单的设置css 代码后,接下来需要添加基础的 TS 准备代码了同鞋悉的童鞋们可能知道这里为啥要使用 TS 了吧,如果还不清楚的,可以去查看我之前写的文章这里咱们依旧使用 TS + ES6语法来进行编写,基础的准备代码如下所示

class StarrySky {canvas: HTMLCanvasElement;ctx: CanvasRenderingContext2D;constructor() {this.canvas = document.createElement('canvas') as HTMLCanvasElement;this.canvas.width = innerWidth;this.canvas.height = innerHeight;this.canvas.style.zIndex = '-1';this.ctx = this.canvas.getContext('2d');document.body.appendChild(this.canvas);}
} 

在基础的准备代码中,我们通过 document.createElement 创建一个 canvas 标签,并给它设置相关宽高和层级,最后通过 document.body.appendChildcanvas 插入body 中。有了以上准备代码后,接下来咱们还需要把动画相关的代码也编写好,相关代码如下所示

class StarrySky {...other code constructor () {...other code }draw() {this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);}animate() {requestAnimationFrame(() => this.animate());this.draw();}
} 

其实现在 canvas 上面已经有了动画了,只是因为还没有绘制内容,因此看不到效果,接下来咱们就该添加星空效果了。

星空效果其实就是很多不同粒子展示canvas 中,因此咱们需要先创建一个 Particle 粒子类,然后通过生成N个粒子,从而在 canvas展示,一起来看一下 Particle 粒子类的相关代码吧,如下

class Particle {x: number;y: number;vx: number;w: number;h: number;ctx: CanvasRenderingContext2D;constructor(width: number, height: number, ctx: CanvasRenderingContext2D) {this.w = width;this.h = height;this.ctx = ctx;this.x = Math.random() * width;this.y = Math.random() * height;this.vx = Math.random();}update() {this.x += this.vx * 3;if (this.x > this.w) {this.x = 0;}}draw() {this.ctx.beginPath();this.ctx.arc(this.x, this.y, 1 + this.vx, 0, Math.PI * 2);this.ctx.fillStyle = `rgba(255, 255, 255, ${this.vx})`;this.ctx.fill();}
} 

Particle 粒子类中我们添加了三个随机值,并在 update 方法中不断更新 x 值的数值,在前面文章中讲过,我们要改变某个元素位置时,只需要改变它沿 x轴y属性即可,因此这里也是一样的;而在 draw 方法中,我们通过 ctx.arc() 方法绘制一个粒子圆,并通过 fillStyle 设置粒子颜色,当 this.vx 值越小时,这个粒子的透明度越低,这样看起来就会显得非常有层次感。

有了 Particle子类接下来咱们就需要在前面StarrySky 类中进行使用了。首先咱们还要对 StarrySky 类中constructor 添加更多的属性,代码如下:

class StarrySky {canvas: HTMLCanvasElement;ctx: CanvasRenderingContext2D;particles: Particle[];count: number;actions: string[];action: number;constructor() {...other codethis.particles = [];this.count = 1000;this.animate();}
} 

可以看到我们constructor新增一个 particles 数组,它主要用于存储生成的粒子类然后我们需要在 StarrySky 类的 draw 方法生成粒子,一起来看代码:

class StarrySky {...other codedraw() {this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);if (this.particles.length < this.count) {this.particles.push(new Particle(this.canvas.width, this.canvas.height, this.ctx));}for (let i in this.particles) {const p = this.particles[i];p.update();p.draw();}}
} 

当我们在 StarrySky 类的 draw 方法中动态生成粒子,并调用对应updatedraw 方法时,最终可以看到如下效果:

通过上图咱们可以看到一幅有层次的星空图已经绘制回来了,但是目前的星空只会向右进行移动,效果还是有些单调,因此咱们接下来通过代码实现点击任何区域让星空的移动能够变换方向,那么该如何实现呢?

变幻的星空图

前面咱们已经通过代码实现了有层次的星空背景绘制了,但是目前可以看到星空的移动只有一个方法,那么该如何修改星空的移动方法呢?还记得在 Particle空类 中的 update 方法吗?在 update 方法中,我们是通过修改当前 this.x 的值从而让粒子实现移动的,因此咱们可以从 update 方法入手,代码如下:

class Particle {...other codeupdate(direction = 'right') {switch (direction) {case 'right':this.x += this.vx * 3;if (this.x > this.w) this.x = 0;break;case 'left':this.x -= this.vx * 3;if (this.x < 0) this.x = this.w;break;case 'up':this.y -= this.vx * 3;if (this.y < 0) this.y = this.h;break;case 'down':this.y += this.vx * 3;if (this.y > this.h) this.y = 0;break;}}
} 

通过修改 Particle 类的 update 方法可以看出,我们通过一个变量判断当前移动的方向,并且设置每个方法不同的值,接下来我们还需要继续修改 StarrySky 类,这样咱们才能实现星空方法的不断变换,一起来看代码:

class StarrySky {...other codeactions: string[];action: number;constructor() {...other codethis.actions = ['right', 'left', 'up', 'down', 'around'];this.action = 0;this.animate();this.event();}event() {document.body.addEventListener('click', () => {this.action++;this.action = this.action % this.actions.length;});}draw() {...other codefor (let i in this.particles) {const p = this.particles[i];p.update(this.actions[this.action]);p.draw();}}
} 

StarrySky 类的 constructor 方法中,我们添加了一个 actions 数组里面包含了上下左右以及旋转五个值,然后还添加了一个 action 变量用于表示当前是第几个,并且通过 document.body.addEventListenerbody 添加了一个 click 事件,当 body点击时,修改当前action,从而改变星空的移动方向。最后StarrySky 类的 draw 方法中,调用 Particle 类的 update 方法时,将当前的移动方向传入即可实现改变星空方向变换的效果了。

当然,咱们还剩下最后一步,还记得上面的 actions 中咱们总共写了五个值,但是在 Particle 类的 update 方法中,咱们只添加了四个 case,因此还剩下最后一个旋转的 case 需要编写,代码如下:

class Particle {...other codeupdate(direction = 'right') {switch (direction) {...other codecase 'around':let deg = Math.atan2(this.y - this.h / 2,this.x - this.w / 2);let r = Math.sqrt(Math.pow(this.x - this.w / 2, 2) + Math.pow(this.y - this.h / 2, 2))this.x = r * Math.cos(deg + this.vx / 200) + this.w / 2;this.y = r * Math.sin(deg + this.vx / 200) + this.h / 2;break;}}
} 

casearound 时,星空需要变换渲染的形式,咱们就需要找到旋转的角度和半径,根据勾股定理三角函数相关的知识,最终获取当前移动的 xy 的值。完整的代码及实现效果如下所示

总结

总的来说,这个效果还是很不错的,并且还添加了相关的交互事件,实现的原理也很简单,有兴趣的童靴可以自己实现一下,本期的内容到此结束

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

原文地址:https://blog.csdn.net/web220507/article/details/128383916

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_34690.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注