aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/web/api/canvas_api/tutorial/advanced_animations/index.html
blob: caacb185aa1723fb5a615ffd1ff6b14b36c38ac8 (plain)
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
---
title: Advanced animations
slug: Web/API/Canvas_API/Tutorial/Advanced_animations
translation_of: Web/API/Canvas_API/Tutorial/Advanced_animations
---
<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}</div>

<div class="summary">
<p>在上一章節,我們做了一些<a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">基礎動畫</a>且知道它的移動方式。在這部分我們更仔細的介紹它的動畫效果且並增加一些特效,使它看起來更高級。</p>
</div>

<h2 id="畫一顆球">畫一顆球</h2>

<p>在這次的動畫練習中使用球來練習。照著下面的步驟完成 canvas 設定。</p>

<pre class="brush: html">&lt;canvas id="canvas" width="600" height="300"&gt;&lt;/canvas&gt;
</pre>

<p>照常理,先在canvas上需要先畫一顆球。創造一個 <code>ball</code> object,它包含的屬性和<code>draw()</code>的方法,使canvas可以在上面繪圖。</p>

<pre class="brush: 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();</pre>

<p>這裡沒什麼特別的,透過{{domxref("CanvasRenderingContext2D.arc()", "arc()")}}的方法,球事實上只是畫下簡單的圓。</p>

<h2 id="添加速度">添加速度</h2>

<p>現在有了一顆球,準備添加基礎的動畫像我們從<a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">上章節學到的課程</a>。再次使用{{domxref("window.requestAnimationFrame()")}}控制動畫。添加移動的向量速度使球移動到向量點。對於每個幀(frame),我們使用{{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}}來清除canvas舊的移動幀(frame)。</p>

<pre class="brush: js; highlight:[8,9,24,25]">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();
</pre>

<h2 id="邊界">邊界</h2>

<p>沒有任何邊界碰撞下,球很快就會跑出canvas。這時需要確認球的 <code>x</code> and <code>y</code> 是否超出 canvas 尺寸,若超出則將球的向量顛倒。所以,我們添加了確認條件在<code>draw</code>方法:</p>

<pre class="brush: js">if (ball.y + ball.vy &gt; canvas.height || ball.y + ball.vy &lt; 0) {
  ball.vy = -ball.vy;
}
if (ball.x + ball.vx &gt; canvas.width || ball.x + ball.vx &lt; 0) {
  ball.vx = -ball.vx;
}</pre>

<h3 id="第一個示範">第一個示範</h3>

<p>讓我們看看,看似很遠的行徑它如何行徑。移動你的滑鼠在canvas,使動畫開始。 </p>

<div class="hidden">
<pre class="brush: html">&lt;canvas id="canvas" style="border: 1px solid" width="600" height="300"&gt;&lt;/canvas&gt;</pre>

<pre class="brush: 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;

  if (ball.y + ball.vy &gt; canvas.height ||
      ball.y + ball.vy &lt; 0) {
    ball.vy = -ball.vy;
  }
  if (ball.x + ball.vx &gt; canvas.width ||
      ball.x + ball.vx &lt; 0) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener('mouseover', function(e) {
  raf = window.requestAnimationFrame(draw);
});

canvas.addEventListener('mouseout', function(e) {
  window.cancelAnimationFrame(raf);
});

ball.draw();</pre>
</div>

<p>{{EmbedLiveSample("First_demo", "610", "310")}}</p>

<h2 id="加速性能">加速性能</h2>

<p>為了使移動看起來更真實,你可以照著範例改變速度:</p>

<pre class="brush: js">ball.vy *= .99;
ball.vy += .25;</pre>

<p>這個使每個幀(frame)的垂直向量減少,所以球將只會在地板彈跳直到結束。</p>

<div class="hidden">
<h6 id="Second_demo">Second demo</h6>

<pre class="brush: html">&lt;canvas id="canvas" style="border: 1px solid" width="600" height="300"&gt;&lt;/canvas&gt;</pre>

<pre class="brush: 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;
  ball.vy *= .99;
  ball.vy += .25;

  if (ball.y + ball.vy &gt; canvas.height ||
      ball.y + ball.vy &lt; 0) {
    ball.vy = -ball.vy;
  }
  if (ball.x + ball.vx &gt; canvas.width ||
      ball.x + ball.vx &lt; 0) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener('mouseover', function(e) {
  raf = window.requestAnimationFrame(draw);
});

canvas.addEventListener('mouseout', function(e) {
  window.cancelAnimationFrame(raf);
});

ball.draw();</pre>
</div>

<p>{{EmbedLiveSample("Second_demo", "610", "310")}}</p>

<h2 id="追蹤效果">追蹤效果</h2>

<p>直到現在我們已經使用{{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}}方法清除之前的幀(frames)。如果使用重置半透明{{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}這個方法,可以更淺顯的看出創造追蹤效果。</p>

<pre class="brush: js">ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);</pre>

<div class="hidden">
<h6 id="Third_demo">Third demo</h6>

<pre class="brush: html">&lt;canvas id="canvas" style="border: 1px solid" width="600" height="300"&gt;&lt;/canvas&gt;</pre>

<pre class="brush: 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.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 *= .99;
  ball.vy += .25;

  if (ball.y + ball.vy &gt; canvas.height ||
      ball.y + ball.vy &lt; 0) {
    ball.vy = -ball.vy;
  }
  if (ball.x + ball.vx &gt; canvas.width ||
      ball.x + ball.vx &lt; 0) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener('mouseover', function(e) {
  raf = window.requestAnimationFrame(draw);
});

canvas.addEventListener('mouseout', function(e) {
  window.cancelAnimationFrame(raf);
});

ball.draw();</pre>
</div>

<p>{{EmbedLiveSample("Third_demo", "610", "310")}}</p>

<h2 id="增加滑鼠控制">增加滑鼠控制</h2>

<p>為了能控制球使它跟著滑鼠移動,在這個範例使用<code><a href="/en-US/docs/Web/Reference/Events/mousemove">mousemove</a></code> 效果。當 <code><a href="/en-US/docs/Web/Events/click">click</a></code> 事件觸發了這顆球,它又會開始彈跳。</p>

<div class="hidden">
<pre class="brush: html">&lt;canvas id="canvas" style="border: 1px solid" width="600" height="300"&gt;&lt;/canvas&gt;</pre>
</div>

<pre class="brush: 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 &gt; canvas.height || ball.y + ball.vy &lt; 0) {
    ball.vy = -ball.vy;
  }
  if (ball.x + ball.vx &gt; canvas.width || ball.x + ball.vx &lt; 0) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener('mousemove', function(e) {
  if (!running) {
    clear();
    ball.x = e.clientX;
    ball.y = e.clientY;
    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();
</pre>

<p>用你的滑鼠移動這顆球且點擊鬆放它。</p>

<p>{{EmbedLiveSample("Adding_mouse_control", "610", "310")}}</p>

<h2 id="突破性(遊戲)">突破性(遊戲)</h2>

<p>這個小章節只有解釋一些創造高級動畫的技巧。這裡還有更多!如何增加槳,磚塊,到這個 到 <a href="http://en.wikipedia.org/wiki/Breakout_%28video_game%29">Breakout</a> game demo去看,有我們更<a href="/en-US/docs/Games">多遊戲研發</a>的文章! </p>

<h2 id="延伸閱讀">延伸閱讀</h2>

<ul>
 <li>{{domxref("window.requestAnimationFrame()")}}</li>
 <li><a href="/en-US/docs/Games/Techniques/Efficient_animation_for_web_games">Efficient animation for web games</a></li>
</ul>

<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}</p>