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

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

我最近搞了一个有趣的项目——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打造真实的雨滴效果的更多相关文章
- Rainyday.js – 使用 JavaScript 实现雨滴效果
Rainyday.js 背后的想法是创建一个 JavaScript 库,利用 HTML5 Canvas 渲染一个雨滴落在玻璃表面的动画.Rainyday.js 有功能可扩展的 API,例如碰撞检测和易 ...
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...
- javascript的canvas绘图的基本用法
<canvas>是HTML里面非常强大的元素,利用它结合js可以实现很多动画效果,大大增强交互性.下面,我想用图文并茂的方式阐述一下canvas的绘图机制的基础内容,话不多说,先上代码: ...
- 使用javascript和canvas画月半弯
使用javascript和canvas画月半弯,月半弯好浪漫!浏览器须支持html5 查看效果:http://keleyi.com/a/bjad/8xqdm0r2.htm 以下是代码: <!do ...
- JavaScript之canvas
num.push(x,y); 动画草图(举个栗子,我们把数字“2”给画出来): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transit ...
- 每天一个JavaScript实例-canvas绘图
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- JavaScript修改Canvas图片
用JavaScript修改Canvas图片的分辨率(DPI) 应用场景: 仓库每次发货需要打印标签, Canvas根据从数据库读取的产品信息可以生成标签JPG, 但是这个JPG图片的默认分辨率(D ...
- html加javascript和canvas类似超级玛丽游戏
html加javascript和canvas制作 代码来源于网上 复制可用 <!doctype html><html lang="en"> <head ...
- JavaScript+html5 canvas实现本地截图教程
这篇文章主要介绍了JavaScript+html5 canvas实现本地截图教程,对截图功能感兴趣的小伙伴们可以参考一下 最近有时间了解了下html5的各API,发现新浪微博的头像设置是使用canva ...
随机推荐
- Sqlserver 日志文件收缩命令
SELECT NAME,recovery_model_desc FROM sys.databases -- 如果是FULL类型,修改为SIMPLE类型 ALTER DATABASE DBName SE ...
- springMVC读取本地图片显示到前端页面
@RequestMapping("/getImage") @ResponseBody public void getImagesId(HttpServletResponse rp) ...
- 并发编程之GIL
目录 GIL 什么是GIL锁 为什么需要加锁 带来的问题 如何解决 关于性能的讨论 计算密集型任务:进程执行更快 IO密集型:线程执行更快 自定义锁与GIL的区别 GIL 什么是GIL锁 官方解释: ...
- 吴裕雄--天生自然PYTHON爬虫:使用Scrapy抓取股票行情
Scrapy框架它能够帮助提升爬虫的效率,从而更好地实现爬虫.Scrapy是一个为了抓取网页数据.提取结构性数据而编写的应用框架,该框架是封装的,包含request异步调度和处理.下载器(多线程的Do ...
- 【python-leetcode25-翻转链表】K 个一组翻转链表
问题描述: 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序. 示例 ...
- MPAndroidChart柱子上的文字的颜色dataSet.setValueTextColors
版本:MPAndroidChart v3.1.0 这是个很强大的图表,不同的版本对应的API会不一样. 需求描述: 用了柱状图,但要实现这样的功能,通过不同的门店来区分不同的柱子的颜色,并且柱子上文字 ...
- springmvc 请求出现400错误(当传入的参数类型是Date时加上下面代码试试)
@InitBinder protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) t ...
- C++中函数访问数组的方式
在书写C++代码时,往往为了令代码更加简洁高效.提高代码可读性,会对定义的函数有一些特殊的要求:比如不传递不必要的参数,以此来让函数的参数列表尽可能简短. 当一个函数需要访问一个数组元素时,出于上述原 ...
- Linux centosVMware PHP动态扩展模块
PHP动态扩展模块 /usr/local/php/bin/php -m //查看模块 下面安装一个redis的模块 cd /usr/local/src/ wget https://codeload.g ...
- heap(堆)
二叉堆: 以前写过二叉堆,但很少使用,快忘了.最近又查了一些关于堆的资料,于是重新熟悉一下这种数据结构. 一个快速又简单的方式建立二叉堆,仅使用简单vector(或者数组也行): #include & ...