使用JavaScript和Canvas打造真实的雨滴效果

寸志 · 1 年前

我最近搞了一个有趣的项目——rainyday.js 。我认为这个项目并不怎么样,而且,事实上这是我第一次尝试接触一些比弹窗更复杂的JavaScript。幸好,你们觉得它还有点意思。
rainyday.js想创建一个轻量的JavaScript类库,利用HTML5的canvas,来实现雨滴在玻璃上滑落的效果。很简单,不过有时候还是很有挑战的,尤其是在我们既要尽力避免动画区别于通常JavaScript的动画,又要保证动画流畅运行的时候。
在本文中,我将对整个方案进行介绍,也会介绍一些细枝末节,请原谅我。不过首先你可能需要先看看下面我准备好的示例,让你自己对我说的有一个真正的概念(点击图片,打开放在JSBin上的示例)。

Canvas图层

为了实现有层次的效果,动画使用了三个canvas,如下图所示。


最下面一层放置原始的图片,使用API将其缩放到需要的大小。图片直接被绘制在canvas上,然后做了模糊处理,看上去像失焦的效果,目前采用的是Mario Klingemann的Stack Blur Algorithm
中间这一层本质上是看不到的。它并不在DOM树中,但是我们可以用它来辅助绘制雨滴的反射效果。图片进行了相应的转置,这可以简化之后的绘制过程。
最后,顶层(玻璃),直接盖在第一层的上面,我们在这一层绘制滑落的雨滴。
整个想法很简单,也很容易理解。相对于一个canvas,分成三层让脚本更加简单,提高了代码的可读性和性能。

深入了解一下雨滴的绘制

对雨滴的渲染是rainday.js最重要的部分。小雨滴想对比较简单,但是对于大雨滴就有好几个因素需要考虑,必须保证雨滴的形状完全是随机的。
为了实现这个目标,rainday.js采用了某种算法使用折线来模拟一个圆形出来(参看Dan Gries的这篇文章Imperfect Circles )。因此,脚本渲染出来的雨滴形状就像下面这样:
算法输出是一系列点的链表,这些点的轨迹就是一个圆。画一个雨滴很简单,把这些点连接起来就行,画的时候,在半径上稍微做点随机就行。然后对我们选作反射的上做剪切就形成了最终的形状。

运行动画

最后的难题就是动画“引擎”。这个动画引擎由三个模块组成。后面的模块依赖于前一个。输出就是你在本文开头demo中看到的效果。这三个模块分别为:
1. rain模块——当调用rain()方法后,就是开启JavaScript的时间定时器。根据用户时间间隔的设置,这个模块会随机的将雨滴放在canvas上。雨滴的大小决定与预设值,因此用户可以控制动画中雨滴的大小和数量。使用demo中的一个作为例子,像下面这样调用rain(),就会每过100ms就在canvas放一个新的水滴。这些水滴大小的分布如下:88%的水滴在3到6之间(最小值3+一个在0到3之间的随机值);2%(0.9 - 0.88)的水滴是5,剩下的10%(1 - 0.9)是6到8之间。

engine.rain([

    engine.preset(3, 3, 0.88),

    engine.preset(5, 5, 0.9),

    engine.preset(6, 2, 1),

], 100);

2. gravity模块——每当水滴加入到动画中后,就会有一个新的定时器出来控制雨滴在canvas上的运动,通过修改它位置的Y坐标来实现(当需要模拟雨滴以一定的角度下落时,使用同样的方法修改其X坐标)。目前rainday.js实现了两种不用的重力函数:GRAVITY_LINEAR(加速度一定的简单重力)和GRAVITY_NON_LINEAR(雨滴的移动看起来更随机一点)。设置重力函数只需要运行如下简单的代码:

engine.gravity = engine.GRAVITY_NON_LINEAR;

3. trail模块——每次雨滴降落时都会运行这个函数,目的是为了绘制雨滴后面的尾巴。TRAIL_DROPS函数实现了由小雨滴组成的尾巴,而TRAIL_NONE则会取消尾巴。如下调用选择雨滴尾巴的效果:

engine.trail = engine.TRAIL_DROPS;

下一步

可以在githubmaroslaw/rainyday.js上找到rainday.js的源码,如果你喜欢,可以去看看。下一个版本(本文是根据0.1.1写的)我会实现雨滴间的碰撞检测,还包括一些我所想到的小的改进。欢迎留言、建议和任何形式的反馈。

原文:Creating a Realistic Rain Effect with Canvas and JavaScript

使用JavaScript和Canvas打造真实的雨滴效果的更多相关文章

  1. Rainyday.js – 使用 JavaScript 实现雨滴效果

    Rainyday.js 背后的想法是创建一个 JavaScript 库,利用 HTML5 Canvas 渲染一个雨滴落在玻璃表面的动画.Rainyday.js 有功能可扩展的 API,例如碰撞检测和易 ...

  2. 使用 JavaScript 和 canvas 做精确的像素碰撞检测

    原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...

  3. javascript的canvas绘图的基本用法

    <canvas>是HTML里面非常强大的元素,利用它结合js可以实现很多动画效果,大大增强交互性.下面,我想用图文并茂的方式阐述一下canvas的绘图机制的基础内容,话不多说,先上代码: ...

  4. 使用javascript和canvas画月半弯

    使用javascript和canvas画月半弯,月半弯好浪漫!浏览器须支持html5 查看效果:http://keleyi.com/a/bjad/8xqdm0r2.htm 以下是代码: <!do ...

  5. JavaScript之canvas

    num.push(x,y); 动画草图(举个栗子,我们把数字“2”给画出来): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transit ...

  6. 每天一个JavaScript实例-canvas绘图

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. JavaScript修改Canvas图片

    用JavaScript修改Canvas图片的分辨率(DPI)   应用场景: 仓库每次发货需要打印标签, Canvas根据从数据库读取的产品信息可以生成标签JPG, 但是这个JPG图片的默认分辨率(D ...

  8. html加javascript和canvas类似超级玛丽游戏

    html加javascript和canvas制作 代码来源于网上 复制可用 <!doctype html><html lang="en"> <head ...

  9. JavaScript+html5 canvas实现本地截图教程

    这篇文章主要介绍了JavaScript+html5 canvas实现本地截图教程,对截图功能感兴趣的小伙伴们可以参考一下 最近有时间了解了下html5的各API,发现新浪微博的头像设置是使用canva ...

随机推荐

  1. java面试(二)

    1.java常见的容器 几乎所有的容器都继承了Collecton接口,包括List.Set.Queue.Map List包括Vector.ArrayList.LinkedList,      Set包 ...

  2. HtmlUnit-API的使用就介绍

    转自:https://www.cnblogs.com/luotinghao/p/3800054.html 网络爬虫第一个要面临的问题,就是如何抓取网页,抓取其实很容易,没你想的那么复杂,一个开源Htm ...

  3. [].slice.call(k).filter(function(l) { return l != 0 });

    [].slice.call(k).filter(function(l) { return l != 0 }); 将类数组调用数组方法.

  4. [ DLPytorch ] 注意力机制&机器翻译

    MachineTranslation 实现过程 rstrip():删除 string 字符串末尾的指定字符(默认为空格). 语法:str.rstrip([chars]) 参数:chars -- 指定删 ...

  5. 学习 Python,怎能不懂点PEP 呢?

    或许你是一个初入门 Python 的小白,完全不知道 PEP 是什么.又或许你是个学会了 Python 的熟手,见过几个 PEP,却不知道这玩意背后是什么.那正好,本文将系统性地介绍一下 PEP,与大 ...

  6. Python 爬取 热词并进行分类数据分析-[解释修复+热词引用]

    日期:2020.02.02 博客期:141 星期日 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备] b.[云图制作+数据导入] c.[拓扑 ...

  7. centos彻底卸载mysql(不保留数据)

    1. rpm -qa | grep -i mysql 查找已经安装的mysql. MySQL-server-5.6.43-1.el6.x86_64 MySQL-client-5.6.43-1.el6. ...

  8. navicat12破解详细教程

    以管理员身份运行此注册机: 运行注册机 打开注册机后,1) Patch勾选Backup.Host和Navicat v12,然后点击Patch按钮: 默认勾选 找到Navicat Premium 12安 ...

  9. 汇编语言从入门到精通-5微机CPU的指令系统2

    微机CPU的指令系统 5.2.2 标志位操作指令 标志位操作指令是一组对标志位置位.复位.保存和恢复等操作的指令. 1.进位CF操作指令 a.清进位指令CLC(Clear Carry Flag):CF ...

  10. ES5中的this

    参考资料:>>> this的指向 在 ES5 中,其实 this 的指向,始终坚持一个原理: this 永远指向最后调用它的那个对象 下面我们来看一个最简单的例子:(例子均来自参考资 ...