长尾效果Canvas动画案例分享

长尾效果,也被称为烟花尾巴效果,是指在烟花爆炸后,其运动轨迹会在空中短暂停留,形成一条尾巴形状。为了实现这种效果,我们不能在绘制新的一帧时完全清除屏幕。相反,我们使用一个透明的黑色背景矩形框来覆盖原有的内容。

这个矩形框的作用是逐渐淡化原有的帧内容,使它们变得越来越透明,直至完全消失。这样,当我们在屏幕上绘制新的烟花时,只有那些新的、未被淡化的部分会显示出来,形成了一种独特的长尾效果。

通过这种方式,我们可以模拟出非常逼真的烟花尾巴效果,给观众带来更加真实和震撼的视觉体验。

让我们看一个长尾效果Canvas动画的例子:

示例效果与源代码:

运行效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<!DOCTYPE html>
<html>

<head>
<title>动画(烟花+长尾)</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="图形系统开发实战:基础篇 示例">
<meta name="author" content="hjq">
<meta name="keywords" content="canvas,ladder,javascript">
<script src="/examples/canvas-qa/canvas_1b/js/helper.js"></script>
</head>

<body style="overflow: hidden; margin:10px;">
<canvas id="canvas" width="800" height="400" style="border:solid 1px #CCCCCC;"></canvas>
<h3>点击画布可产生烟花</h3>
</body>
<script>
// 从页面中获取画板对象
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let fireworks = [];
let debug = false, times = 0;

// 黑色背景
ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制背景网格
drawGrid('lightgray', 0, 0, ctx);

/**
* 烟花类
*/
class Firework {
constructor(x, y) {
this.x = x;
this.y = y;

// 火花数
this.sparkCount = 10;
// 火花大小
this.sparkSize = 2;
// 火花半径
this.sparkRadius = 10;

// 重力
this.gravity = 1;
// 扩散速度
this.speed = 2;
// 扩散速度衰减率
this.decay = 0.98;
}

// 绘制烟花
draw() {
for (let i = 0; i < this.sparkCount; i++) {
let angle = i * 360 / this.sparkCount;
let cx = this.x + Math.cos(toRadians(angle)) * this.sparkRadius
let cy = this.y + Math.sin(toRadians(angle)) * this.sparkRadius
ctx.beginPath();
ctx.arc(cx, cy, this.sparkSize, Math.PI * 2, false);
ctx.closePath();
ctx.fillStyle = "#FF0000";
ctx.fill();
}
}

// 更新烟花大小、位置、透明度
update() {
// 烟花随重力落下
this.y += this.gravity;
// 烟花半径随速度扩散
this.sparkRadius = this.sparkRadius + this.speed;
// 烟花扩散速度衰减
this.speed = this.speed * this.decay;
// 火花大小随时间放大
this.sparkSize = this.sparkSize < 7 ? this.sparkSize + 0.02 : this.sparkSize;
return this.sparkRadius < 100;
}
}

// 帧动画
function frame() {

if (times % 6 === 0 || debug === false) {
// 绘制黑色透明背景,可产生长尾效果
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawGrid('lightgray', 0, 0, ctx);

// 绘制烟花
for (let i = fireworks.length - 1; i >= 0; i--) {
fireworks[i].draw();
if (!fireworks[i].update()) {
fireworks.splice(i, 1);
}
}
}
window.requestAnimationFrame(frame);
}
window.requestAnimationFrame(frame);

// 点击画布,产生烟花
canvas.addEventListener('click', function (e) {
fireworks.push(new Firework(e.offsetX, e.offsetY));
});

</script>

</html>

尝试一下 »