使用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 IO流详解(五)——缓冲流

    缓冲流也叫高效流,是处理流的一种,即是作用在流上的流.其目的就是加快读取和写入数据的速度. 缓冲流本身并没有IO功能,只是在别的流上加上缓冲效果从而提高了效率.当对文件或其他目标频繁读写或操作效率低, ...

  2. 【PAT甲级】1051 Pop Sequence (25 分)(栈的模拟)

    题意: 输入三个正整数M,N,K(<=1000),分别代表栈的容量,序列长度和输入序列的组数.接着输入K组出栈序列,输出是否可能以该序列的顺序出栈.数字1~N按照顺序随机入栈(入栈时机随机,未知 ...

  3. Hive的mysql安装配置

    一.MySQL的安装 Hive的数据,是存在HDFS里的.此外,hive有哪些数据库,每个数据库有哪些表,这样的信息称之为hive的元数据信息. 元数据信息不存在HDFS,而是存在关系型数据库里,hi ...

  4. PB specified database is invalid

    拷贝资料库到其他机器,可以重新配置ODBC ,如果还是报错,建议删除log .

  5. idea取消参数标记

  6. centos 安装phpize

    yum -y install php-devel 然后 /usr/bin/phpize

  7. 操作系统OS - 线程中的join()为什么叫join

    1. 问题:很好奇为什么叫Join? 参考: https://blog.csdn.net/frankarmstrong/article/details/55504161 https://stackov ...

  8. TCP通讯代码

    服务端代码: import socket server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 使用固定端口 server_ ...

  9. 【已解决】iOS11使用MJRefresh上拉加载结束tableView闪动、跳动的问题

    更新提示: [2018年11月20日更新] 经过放置在项目中运行发现,如果在快速滚动tableview的时候会在下面这行代码中崩溃(慢慢的滚动是没关系的-): CGFloat cellHeight = ...

  10. 使用SQL语句还原数据库 2012.3.20

    --返回由备份集内包含的数据库和日志文件列表组成的结果集. --主要获得逻辑文件名 USE master RESTORE FILELISTONLY FROM DISK = 'g:\back.Bak' ...