/
index.md
403 lines (311 loc) · 9.52 KB
/
index.md
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
---
title: 高级动画
slug: Web/API/Canvas_API/Tutorial/Advanced_animations
---
{{DefaultAPISidebar("Canvas API")}} {{ PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}
在上一章,我们制作了[基本动画](/zh-CN/docs/Web/Guide/HTML/Canvas_tutorial/Basic_animations)以及逐步了解了让物件移动的方法。在这一部分,我们将会对运动有更深的了解并学会添加一些符合物理的运动以让我们的动画更加高级。
## 绘制小球
我们将会画一个小球用于动画学习,所以首先在画布上画一个球。下面的代码帮助我们建立画布。
```html
<canvas id="canvas" width="600" height="300"></canvas>
```
跟平常一样,我们需要先画一个 context(画布场景)。为了画出这个球,我们又会创建一个包含一些相关属性以及 `draw()` 函数的 `ball` 对象,来完成绘制。
```js
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var ball = {
x: 100,
y: 100,
radius: 25,
color: "blue",
draw: function () {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
ball.draw();
```
这里并没有什么特别的。小球实际上是一个简单的圆形,在{{domxref("CanvasRenderingContext2D.arc()", "arc()")}} 函数的帮助下画出。
## 添加速率
现在我们有了一个小球,正准备添加一些基本动画,正如我们[上一章](/zh-CN/docs/Web/API/Canvas_API/Tutorial/Basic_animations)所学的。又是这样,{{domxref("window.requestAnimationFrame()")}} 再一次帮助我们控制动画。小球依旧依靠添加速率矢量进行移动。在每一帧里面,我们依旧用{{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}} 清理掉之前帧里旧的圆形。
```js
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var raf;
var ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw: function () {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", function (e) {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", function (e) {
window.cancelAnimationFrame(raf);
});
ball.draw();
```
## 边界
若没有任何的碰撞检测,我们的小球很快就会超出画布。我们需要检查小球的 x 和 y 位置是否已经超出画布的尺寸以及是否需要将速度矢量反转。为了这么做,我们把下面的检查代码添加进 `draw` 函数:
```js
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
```
### 首个示例
让我们看看现今它变得如何。
#### HTML
```html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
```
#### JavaScript
```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
```
#### 结果
移动你的鼠标到画布里开启动画。
{{EmbedLiveSample("首个示例", "610", "340")}}
## 加速度
为了让动作更真实,你可以像这样处理速度,例如:
```js
ball.vy *= 0.99;
ball.vy += 0.25;
```
这会逐帧减少垂直方向的速度,所以小球最终将只会在地板上弹跳。
### 第二个示例
#### HTML
```html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
```
#### JavaScript
```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy *= 0.99;
ball.vy += 0.25;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
```
#### 结果
{{EmbedLiveSample("第二个示例", "610", "340")}}
## 长尾效果
现在,我们使用的是 {{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}} 函数帮我们清除前一帧动画。若用一个半透明的 {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}} 函数取代之,就可轻松制作长尾效果。
```js
ctx.fillStyle = "rgba(255,255,255,0.3)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
```
### 第三个示例
#### HTML
```html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
```
#### JavaScript
```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy *= 0.99;
ball.vy += 0.25;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
```
#### 结果
{{EmbedLiveSample("第三个示例", "610", "340")}}
## 添加鼠标控制
为了更好地控制小球,我们可以用 [`mousemove`](/zh-CN/docs/Web/Reference/Events/mousemove)事件让它跟随鼠标活动。下面例子中,[click](/zh-CN/docs/Web/Events/click) 事件会释放小球然后让它重新跳起。
```html hidden
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
```
```js
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var raf;
var running = false;
var ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 25,
color: "blue",
draw: function () {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function clear() {
ctx.fillStyle = "rgba(255,255,255,0.3)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function draw() {
clear();
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mousemove", function (e) {
if (!running) {
clear();
ball.x = e.offsetX;
ball.y = e.offsetY;
ball.draw();
}
});
canvas.addEventListener("click", function (e) {
if (!running) {
raf = window.requestAnimationFrame(draw);
running = true;
}
});
canvas.addEventListener("mouseout", function (e) {
window.cancelAnimationFrame(raf);
running = false;
});
ball.draw();
```
用你的鼠标移动小球,点击可以释放。
{{EmbedLiveSample("添加鼠标控制", "610", "310")}}
## Breakout
本短文仅仅解释了一小部分的创建高级动画的技巧。其实还有更多!试试添加一个球拍,一些砖块,然后将这个例子弄成一个 [Breakout](http://en.wikipedia.org/wiki/Breakout_%28video_game%29)(译者注:打砖块游戏)如何?查看我们的[游戏开发](/zh-CN/docs/Games)区去查阅更多相关文章。
## 参考
- {{domxref("window.requestAnimationFrame()")}}
- [网页动画高效开发](/zh-CN/docs/Games/Techniques/Efficient_animation_for_web_games)
{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}