烟花特效-Canvas解决方案

烟花动画效果是一种非常美丽和壮观的视觉效果,它能够给观众带来愉悦和惊叹的感受。在制作烟花动画效果时,需要考虑多个因素,包括烟花的颜色、形状、爆炸速度、飞行轨迹等。

首先,我们需要确定烟花的颜色和形状。颜色可以通过不同的颜色混合来实现,而形状可以通过粒子系统或3D模型来创建。在形状方面,我们可以设计不同大小和形状的烟花,如球形、圆柱形、圆锥形等,以增加多样性和真实感。

其次,我们需要控制烟花的爆炸速度和飞行轨迹。爆炸速度可以通过粒子系统的发射速度来调整,而飞行轨迹可以通过物理引擎来模拟。在模拟飞行轨迹时,我们需要考虑重力和空气阻力的影响,以使烟花在空中的运动轨迹更加自然和逼真。

此外,我们还需要控制烟花的亮度和颜色变化。可以通过粒子系统的颜色变化来实现,以使烟花在空中的颜色更加丰富和多彩。

最后,我们需要将烟花动画效果与背景音乐和特效相配合,以营造更加浪漫和神秘的氛围。例如,可以在烟花绽放时添加一些闪烁的星星或爱心形状的特效,以增加视觉效果的美感和趣味性。

总的来说,烟花动画效果是一种非常美丽和壮观的视觉效果,它需要制作人员具备扎实的计算机图形学技能和创意,以便能够准确地模拟和呈现各种美丽的烟花效果。

让我们看一个烟花特效的例子:

示例效果与源代码:

运行效果

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!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><br>
<div class="checkbox" style="margin-top:10px;">
<span style="font-size:20px;">点击画布可产生烟花</span>
<label style="margin-left:500px;"><input id="chkAuto" type="checkbox" checked>自动产生烟花</label>
</div>
</body>
<script>
// 从页面中获取画板对象
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let fireworks = [];
let debug = false, times = 0, lastTime, fps = 0, timeRatio = 1;

// 黑色背景
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 = getRandomNum(5, 14);
// 火花大小
this.sparkSize = 2;
// 火花半径
this.sparkRadius = 10;

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

// 透明度
this.alpha = 1;
// 颜色
this.color = 15 * getRandomNum(0, 24);
}

// 绘制烟花
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 = "hsl(" + this.color + ",100%, 50%," + this.alpha + ")";
ctx.fill();
}
}

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

// 随机在指定位置附近产生烟花
function randomFireworks(x, y) {
let num = getRandomNum(5, 10);
for (let i = 0; i < num; i++) {
fireworks.push(new Firework(x + getRandomNum(-50, 50), y + getRandomNum(-50, 50)));
}
}

// 计算帧率
function calculateFps() {
times++;
// 当前秒数大于上一次绘制时钟的秒数时,重新计算帧率
if (Date.now() >= lastTime + 1000) {
fps = times;
timeRatio = 60 / fps;
times = 0;
lastTime = Date.now();
}
}

// 帧动画
function frame() {
// 计算帧率
calculateFps();

if (times % 60 === 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()) {
// 当烟花的透明度小于0.1时,删除该烟花
fireworks.splice(i, 1);
}
}

// 当烟花数小于10时,重新生产烟花
if (!debug && fireworks.length < 10 && document.getElementById("chkAuto").checked === true) {
randomFireworks(getRandomNum(50, canvas.width - 50), getRandomNum(50, canvas.height - 100));
}
}
window.requestAnimationFrame(frame);
}
window.requestAnimationFrame(frame);

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

</script>

</html>

此示例中我们通过帧率来计算移动距离的思路来解决不同屏幕刷新率的电脑上将会出现不同的播放速度的问题。我们知道fps代表每秒重绘帧的次数,常见的屏幕刷新率是60Hz,当fps等于30时,间隔时间为fpt等于60的两倍; 当fps等于120时,间隔时间为fpt等于60的0.5倍。由于 距离=速度×时间,利用该公式就可实现在不同帧率的电脑上相同的时间移动相同的距离的效果。