这个动画在很早之前就见过,当时就没迷住了。最近在学canavs动画,动手实现了一下。代码在这里。展示效果在这里。

这属于粒子系统的一种,粒子系统就是需要管理一堆粒子嘛,动画实现的关键在于,遍历这些粒子,并更新它们的位置。

粒子

每个粒子都需要包含自己的横纵坐标想x、y,半径r,各分量上的加速度ax、ay,速度vx、vy,还有所属的场景owner,这里的粒子加速度均为0。

// 父类
class Sprite {
constructor(args={}) {
this.x = args.x || 0;
this.y = args.y || 0;
this.vx = args.vx || 0;
this.vy = args.vy || 0;
this.ax = args.ax || 0;
this.ay = args.ay || 0;
} moveTo(x, y) {
this.x = x;
this.y = y;
} update() {
this.vx += this.ax;
this.vy += this.ay; this.x += this.vx;
this.y += this.vy;
} render() {
return true;
}
}

// 粒子
class Particle extends Sprite{
constructor(args) {
super(args);
this.owner = args.owner;
this.r = args.r || 10;
this.color = args.color || 'black'; this.adjust = this.adjust.bind(this);
} update() {
super.update();
if(this.x < this.r || this.x + this.r > this.owner.w) {
this.vx *= -1;
this.x = this.adjust(0, this.owner.w, this.x);
} if(this.y < this.r || this.y + this.r > this.owner.h) {
this.vy *= -1;
this.y = this.adjust(0, this.owner.h, this.y);
}
} render(ctx) {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
} adjust(min, max, v) {
return v > max ? max : (v < min ? min : v);
}
}

父类的update()中用于改变对象的坐标,particle类的update()在调用了父类的update方法之后,进行边界检测。

边界检测

边界检测属于碰撞检测的一种。在改变粒子位置之后,对粒子进行边界检测,防止粒子逃出canvas哦。本例中的粒子是圆形的,可以通过粒子中心点与边界之间的距离进行判断,若小于粒子自身半径,则对粒子坐标进行修正,确保粒子始终位于canvas中。

/*
* this.x 粒子横坐标
* this.y 粒子纵坐标
* this.r 粒子半径
* this.owner.w 粒子所在场景(canvas)宽度
* this.owner.h 粒子所在场景(canvas)高度
*/
if(this.x < this.r || this.x + this.r > this.owner.w) {
this.vx *= -1;
this.x = this.adjust(0, this.owner.w, this.x);
} if(this.y < this.r || this.y + this.r > this.owner.h) {
this.vy *= -1;
this.y = this.adjust(0, this.owner.h, this.y);
}

当粒子坐标超出边界时,使用adjust()重置粒子坐标,确保粒子在canvas内。

adjust(min, max, v) {
return v > max ? max : (v < min ? min : v);
}

粒子系统

粒子系统就是对粒子进行管理的。

this.nodes = [];   // 保存粒子
this.edges = []; // 粒子成对保存,用于连线

存储edges时,使用双层循环,内循环n的从i + 1开始,避免重复保存。

for(let i = 0, len = this.nodes.length; i < len; ++i) {
for(let n = i + 1; n < len; ++n) {
this.edges.push({
from: this.nodes[i],
to: this.nodes[n]
})
}
}

计算两个粒子之间的距离。

lengthOfEdge(edge) {
let w = Math.abs(edge.from.x - edge.to.x),
h = Math.abs(edge.from.y - edge.to.y);
return Math.sqrt(w * w + h * h);
}

粒子间距离越短,连线越粗、越深。

this.ctx.lineWidth = (1 - l / this.threshold) * 2.5;
this.ctx.globalAlpha = 1 - l / this.threshold;

超出一定距离就不连线。

let l = this.lengthOfEdge(edge);
if(l > this.threshold) {
return;
}

鼠标事件

这里为了与用户有互动,加入了鼠标事件。当鼠标在canvas内移动时,第一个粒子nodes[0]的跟随鼠标移动。当鼠标静止或者在canvas外时,则按照原来的速度进行移动。

mouserEnter(e) {
this.mouse = this.nodes[0];
} mouseMove(e) {
this.mouse.x = e.offsetX;
this.mouse.y = e.offsetY;
} mouseLeave() {
this.mouse = null;
}

至于动画的更新,建议使用requestAnimationFrame()。

canvas——粒子系统(1)的更多相关文章

  1. canvas粒子系统的构建

    前面的话 本文将从最基本的imageData对象的理论知识说开去,详细介绍canvas粒子系统的构建 效果演示 下面是实例效果演示,博文结尾有全部源码 imageData 关于图像数据imageDat ...

  2. HTML5的新结构标签

    在之前的HTML页面中,大家基本上都是用了Div+CSS的布局方式.而搜索引擎去抓取页面的内容的时候,它只能猜测你的某个Div内的内容是文章内容容器,或者是导航模块的容器,或者是作者介绍的容器等等.也 ...

  3. canvas动画——粒子系统(1)

    这个动画在很早之前就见过,当时就没迷住了.最近在学canavs动画,动手实现了一下.代码在这里.展示效果在这里. 这属于粒子系统的一种,粒子系统就是需要管理一堆粒子嘛,动画实现的关键在于,遍历这些粒子 ...

  4. canvas绘图基础及基于粒子系统的雪花飘落

    canvas是html中的一个元素,可以通过js操控绘图! 可以绘制各种图形,各种填充样式! 绘制时可以进行旋转,缩放,平移,但并不是很灵活! 有一对比较好用的方法是save restore! sav ...

  5. 粒子系统(二):Canvas绘制精美图案

    准备 IDE:Visual Studio Code Language:JavaScript / ECMAScript 6+ GitHub:Natural2D.JS 本文主要讲述 Particles - ...

  6. Three.js开发指南---粒子和粒子系统(第七章)

    使用粒子可以很容易的创建很多细小的物体,例如雨滴雪花等 本章主要内容: 1 使用ParticleBasicMaterial(基础粒子材质)来创建和设计粒子 2 使用ParticleSystem来创建一 ...

  7. three.js入门系列之粒子系统

    其实代码很简单,也很容易懂(我用的是r99版本的three.js,目前网上大多数demo是60或者80的版本,其中的一些api已经废弃,如下是r99版本支持的写法): 注:渲染器是WebGl渲染器 如 ...

  8. canvas绘制经典星空连线效果

    来自:https://segmentfault.com/a/1190000009675230 下面开始coding:先写个canvas标签 <canvas height="620&qu ...

  9. 基于canvas与原生JS的H5动画引擎

    前一段时间项目组里有一些H5动画的需求,由于没有专业的前端人员,便交由我这个做后台的研究相关的H5动画技术. 通过初步调研,H5动画的实现大概有以下几种方式: 1.基于css实现 这种方式比较简单易学 ...

随机推荐

  1. [TypeScript] Simplify asynchronous callback functions using async/await

    Learn how to write a promise based delay function and then use it in async await to see how much it ...

  2. Django + Apache + wsgi配置和环境搭建(ubuntu)

    上一篇写了Django + nginx + uwsgi配置和环境搭建(ubuntu) 由于公司服务器环境问题,又配置了apache的环境.记录例如以下: 一. 安装环境: #apache sudo a ...

  3. C++ 计算任意两个日期之间的天数

    C++写的一个计算两个日期之间天数的小程序: #include <Windows.h> #include <stdio.h> struct tagDate { int year ...

  4. 辛星浅析yaf框架中的类的自己主动载入问题

    因为公司非常多项目都是基于yaf的,而非常多刚接触yaf的朋友问的第一个问题就是:yaf的自己主动载入是依照什么规则来的. 鉴于此.于是我特别开了一篇博文来记录一下. 首先在yaf中.models文件 ...

  5. dom对象常用的属性和方法有哪些?

    dom对象常用的属性和方法有哪些? 一.总结 一句话总结: 1.document属性和方法:document的属性有head,body之类,方法有各种获取element的方法 2.element的属性 ...

  6. 单个和多个checkbox选中事件怎么写

    单个和多个checkbox选中事件怎么写 一.总结 一句话总结: 1.checkbox的事件方法的话主要是change和click 2.checkbox的属性判断的话主要是prop(判断checked ...

  7. [读书笔记]《Android开发艺术探索》第十五章笔记

    Android性能优化 Android不可能无限制的使用内存和CPU资源,过多的使用内存会导致内存溢出,即OOM. 而过多的使用CPU资源,通常是指做大量的耗时任务,会导致手机变的卡顿甚至出现程序无法 ...

  8. jQuery树形菜单,使用zTree插件,异步载入 &amp; 编辑功能&amp;Check 共存

    一.下载zTree插件 地址:http://www.ztree.me 二.HTML代码 <%@ Page Language="C#" AutoEventWireup=&quo ...

  9. SecondaryNameNode 的作用

    Secondary NameNode:它究竟有什么作用? 尽量不要将 secondarynamede 和 namenode 放在同一台机器上. 1. NameNode NameNode 主要是用来保存 ...

  10. linux下Java程序中插入DB中国的数据乱码问题

    首先,插入到DB数据,在Linux在查询时,现场展示??. 再次,在windows连接到db上,查看的结果并非乱码. 改动Eclipse软件中的编码:如上图:windows菜单->prefere ...