aboutsummaryrefslogtreecommitdiff
path: root/files/ko/web/html/canvas/tutorial/basic_animations/index.html
blob: 457d65817273e98f2e592aa3ae3992c12826d47a (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
---
title: 기본 애니메이션
slug: Web/HTML/Canvas/Tutorial/Basic_animations
tags:
  - HTML5
  - 그래픽
  - 캔버스
translation_of: Web/API/Canvas_API/Tutorial/Basic_animations
---
<p>{{HTMLElement("canvas")}} 요소는 자바스크립트로 제어하는 것이므로, 애니메이션도 쉽게 만들 수 있습니다. 복잡한 애니메이션을 만드는 것은 추가 작업이 더 필요하고, 앞으로 그에 대한 페이지도 머지 않아 추가되기를 기대합니다.</p>
<p>도형은 한번 만들어 놓으면 그 모습 그대로 있다는 것이 애니메이션을 만들 때의 가장 큰 제약일 것입니다. 그 도형을 움직이고자 하면 그 도형뿐만이 아니라 그 도형이 그려지기 전에 그려진 모든 것을 다시 그려야 합니다. 복잡한 장면을 다시 그리는 것은 시간도 많이 걸리며, 코드를 실행하는 컴퓨터의 능력에 따라 달라집니다.</p>
<h2 id="Basic_animation_steps" name="Basic_animation_steps">기본 애니메이션 단계</h2>
<p>한 장면을 그리려면 아래와 같은 단계를 밟습니다.</p>
<ol>
 <li><strong>캔버스를 비웁니다.</strong><br>
  그리려는 도형이 (배경 이미지를 만들 때처럼) 캔버스를 가득 채우는 것이 아니라면, 이전에 그려진 모든 도형을 지울 필요가 있습니다. 가장 쉬운 방법은 <code>clearRect()</code> 메소드를 사용하는 것입니다.</li>
 <li><strong>캔버스 상태를 저장합니다.</strong><br>
  캔버스 상태에 영향을 주는 (스타일 변경, 모양 변형 등의) 설정값을 바꾸려고 하고, 바뀐 값을 각 장면마다 사용하려고 한다면, 원래 상태를 저장할 필요가 있습니다.</li>
 <li><strong>애니메이션할 도형을 그립니다.</strong><br>
  실제 장면을 그리는 단계입니다.</li>
 <li><strong>캔버스 상태를 복원합니다.</strong><br>
  새로운 장면을 그리기 전에 저장된 상태를 복원합니다.</li>
</ol>
<h2 id="Controlling_an_animation" name="Controlling_an_animation">애니메이션 제어하기</h2>
<p>캔버스 메소드를 사용하거나 사용자 함수를 사용하여 캔버스에 도형들을 그립니다. 보통의 경우에서는, 코드 실행이 완료되면 캔버스에 나타나는 결과만을 보게 됩니다. 예를 들어,  <code>for</code> 반복문 안에서 애니메이션을 실행하는 것은 불가능합니다.</p>
<p>그래서 정해진 시간마다 그리기 함수를 실행하는 방법이 필요한 것입니다. 아래와 같이 애니메이션을 제어하는 두 가지 방법이 있습니다.</p>
<h3 id="예정된_변경">예정된 변경</h3>
<p>정해진 시간마다 특정 함수를 부를 때 사용할 수 있는  {{domxref("window.setInterval()")}}{{domxref("window.setTimeout()")}} 함수가 있습니다.</p>
<div class="note">
 <p>알아둘 것: 현재는 애니메이션을 만드는 방법으로  {{domxref("window.requestAnimationFrame()")}} 메소드를 추천합니다. 이에 대한 튜토리얼은 곧 업데이트할 것입니다.</p>
</div>
<dl>
 <dt>
  <code>setInterval(<em>function</em>, <em>delay</em>)</code></dt>
 <dd>
  <code>delay</code> 밀리세컨드(1,000분의 1초)마다 <code>function</code> 함수 반복 실행을 시작합니다.</dd>
 <dt>
  <code>setTimeout(<em>function</em>, <em>delay</em>)</code></dt>
 <dd>
  <code>delay</code> 밀리세컨드(1,000분의 1초) 경과후, <code>function</code> 함수를 실행합니다.</dd>
</dl>
<p>사용자의 제어를  <strong>필요로 하지 않는</strong> 반복 실행에는  <code>setInterval()</code> 함수가 알맞을 것입니다.</p>
<h3 id="사용자_상호_작용_변경">사용자 상호 작용 변경</h3>
<p>애니메이션을 제어하는 두번째 방법은 사용자 입력입니다. 게임을 만들려고 한다면, 애니메이션을 제어하기 위해 키보드나 마우스 이벤트를 사용할 수 있을 것입니다.  {{domxref("EventListener")}}를 설정하여, 사용자와 상호 작용하여 애니메이션 함수를 실행합니다.</p>
<p>사용자 상호 작용이 <strong>필요하다면</strong>, 우리가 만든 <a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">애니메이션용 프레임웍(framework)</a><a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework">최소 기능 버전</a> 또는 <a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">최대 기능 버전</a>을 사용할 수 있을 것입니다.</p>
<pre>var myAnimation = new MiniDaemon(null, animateShape, 500, Infinity);</pre>
<p>또는</p>
<pre>var myAnimation = new Daemon(null, animateShape, 500, Infinity);</pre>
<p>아래 예제에서는, 애니메이션을 제어하기 위해 {{domxref("window.setInterval()")}}을 사용할 것입니다. 페이지 제일 아래쪽에 {{domxref("window.setTimeout()")}}을 사용한 예제 링크도 있습니다.</p>
<h4 id="태양계_애니메이션">태양계 애니메이션</h4>
<p>이 예제에서는 달이 지구를 돌고 지구가 태양을 도는 애니메이션을 만듭니다.</p>
<pre class="brush: js">var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
  earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
  setInterval(draw,100);
}

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  ctx.globalCompositeOperation = 'destination-over';
  ctx.clearRect(0,0,300,300); // 캔버스를 비운다

  ctx.fillStyle = 'rgba(0,0,0,0.4)';
  ctx.strokeStyle = 'rgba(0,153,255,0.4)';
  ctx.save();
  ctx.translate(150,150);

  // 지구
  var time = new Date();
  ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
  ctx.translate(105,0);
  ctx.fillRect(0,-12,50,24); // Shadow
  ctx.drawImage(earth,-12,-12);

  // 달
  ctx.save();
  ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
  ctx.translate(0,28.5);
  ctx.drawImage(moon,-3.5,-3.5);
  ctx.restore();

  ctx.restore();

  ctx.beginPath();
  ctx.arc(150,150,105,0,Math.PI*2,false); // 지구 궤도
  ctx.stroke();

  ctx.drawImage(sun,0,0,300,300);
}
</pre>
<div class="hidden">
 <pre class="brush: html">&lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;</pre>
 <pre class="brush: js">init();</pre>
</div>
<p>{{EmbedLiveSample("An_animated_solar_system", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}</p>
<h4 id="시계_애니메이션">시계 애니메이션</h4>
<p>이 예제에서는, 현재 시각을 보여주는 움직이는 시계를 만듭니다.</p>
<pre class="brush: js">function init(){
  clock();
  setInterval(clock,1000);
}

function clock(){
  var now = new Date();
  var ctx = document.getElementById('canvas').getContext('2d');
  ctx.save();
  ctx.clearRect(0,0,150,150);
  ctx.translate(75,75);
  ctx.scale(0.4,0.4);
  ctx.rotate(-Math.PI/2);
  ctx.strokeStyle = "black";
  ctx.fillStyle = "white";
  ctx.lineWidth = 8;
  ctx.lineCap = "round";

  // 시계판 - 시
  ctx.save();
  for (var i=0;i&lt;12;i++){
    ctx.beginPath();
    ctx.rotate(Math.PI/6);
    ctx.moveTo(100,0);
    ctx.lineTo(120,0);
    ctx.stroke();
  }
  ctx.restore();

  // 시계판 - 분
  ctx.save();
  ctx.lineWidth = 5;
  for (i=0;i&lt;60;i++){
    if (i%5!=0) {
      ctx.beginPath();
      ctx.moveTo(117,0);
      ctx.lineTo(120,0);
      ctx.stroke();
    }
    ctx.rotate(Math.PI/30);
  }
  ctx.restore();

  var sec = now.getSeconds();
  var min = now.getMinutes();
  var hr  = now.getHours();
  hr = hr&gt;=12 ? hr-12 : hr;

  ctx.fillStyle = "black";

  // 시간 표시 - 시
  ctx.save();
  ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
  ctx.lineWidth = 14;
  ctx.beginPath();
  ctx.moveTo(-20,0);
  ctx.lineTo(80,0);
  ctx.stroke();
  ctx.restore();

  // 시간 표시 - 분
  ctx.save();
  ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
  ctx.lineWidth = 10;
  ctx.beginPath();
  ctx.moveTo(-28,0);
  ctx.lineTo(112,0);
  ctx.stroke();
  ctx.restore();

  // 시간 표시 - 초
  ctx.save();
  ctx.rotate(sec * Math.PI/30);
  ctx.strokeStyle = "#D40000";
  ctx.fillStyle = "#D40000";
  ctx.lineWidth = 6;
  ctx.beginPath();
  ctx.moveTo(-30,0);
  ctx.lineTo(83,0);
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0,0,10,0,Math.PI*2,true);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(95,0,10,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fillStyle = "rgba(0,0,0,0)";
  ctx.arc(0,0,3,0,Math.PI*2,true);
  ctx.fill();
  ctx.restore();

  ctx.beginPath();
  ctx.lineWidth = 14;
  ctx.strokeStyle = '#325FA2';
  ctx.arc(0,0,142,0,Math.PI*2,true);
  ctx.stroke();

  ctx.restore();
}</pre>
<div class="hidden">
 <pre class="brush: html">&lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;</pre>
 <pre class="brush: js">init();</pre>
</div>
<p>{{EmbedLiveSample("An_animated_clock", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}</p>
<h4 id="움직이는_파노라마_사진">움직이는 파노라마 사진</h4>
<p>이 예제에서는, 움직이는 파노라마 사진을 만듭니다. 사용할 그림은 위키피디어(Wikipedia)에서 구한 <a href="http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg" title="http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg">요세미티 국립공원</a>입니다. 캔버스보다 큰 그림을 사용할 수도 있습니다.</p>
<pre class="brush: js">var img = new Image();

// 변수
// 스크롤될 이미지, 방향, 속도를 바꾸려면 변수값을 바꾼다.

img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg';
var CanvasXSize = 800;
var CanvasYSize = 200;
var speed = 30; // 값이 작을 수록 빨라진다
var scale = 1.05;
var y = -4.5; // 수직 옵셋

// 주요 프로그램

var dx = 0.75;
var imgW;
var imgH;
var x = 0;
var clearX;
var clearY;
var ctx;

img.onload = function() {
    imgW = img.width*scale;
    imgH = img.height*scale;
    if (imgW &gt; CanvasXSize) { x = CanvasXSize-imgW; } // 캔버스보다 큰 이미지
    if (imgW &gt; CanvasXSize) { clearX = imgW; } // 캔버스보다 큰 이미지
    else { clearX = CanvasXSize; }
    if (imgH &gt; CanvasYSize) { clearY = imgH; } // 캔버스보다 큰 이미지
    else { clearY = CanvasYSize; }
    // 캔버스 요소 얻기
    ctx = document.getElementById('canvas').getContext('2d');
    // 새로 그리기 속도 설정
    return setInterval(draw, speed);
}

function draw() {
    // 캔버스를 비운다
    ctx.clearRect(0,0,clearX,clearY);
    // 이미지가 캔버스보다 작거나 같다면 (If image is &lt;= Canvas Size)
    if (imgW &lt;= CanvasXSize) {
        // 재설정, 처음부터 시작
        if (x &gt; (CanvasXSize)) { x = 0; }
        // 추가 이미지 그리기
        if (x &gt; (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); }
    }
    // 이미지가 캔버스보다 크다면 (If image is &gt; Canvas Size)
    else {
        // 재설정, 처음부터 시작
        if (x &gt; (CanvasXSize)) { x = CanvasXSize-imgW; }
        // 추가 이미지 그리기
        if (x &gt; (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); }
    }
    // 이미지 그리기
    ctx.drawImage(img,x,y,imgW,imgH);
    // 움직임 정도
    x += dx;
}
</pre>
<p>예제에 사용된 {{HTMLElement("canvas")}}의 크기는 아래와 같다. 캔버스의 너비가 변수 <code>CanvasXSize</code>값과 같고, 캔버스의 높이는 변수 <code>CanvasYSize</code>값과 같다는 것에 주목하라.</p>
<pre class="brush: html">&lt;canvas id="canvas" width="800" height="200"&gt;&lt;/canvas&gt;</pre>
<p><strong>Live sample</strong></p>
<p>{{EmbedLiveSample("A_looping_panorama", "830", "230")}}</p>
<h2 id="Other_examples" name="Other_examples">또 다른 예제들</h2>
<dl>
 <dt>
  <a class="external" href="http://www.gartic.net/" title="http://www.gartic.net/">Gartic</a></dt>
 <dd>
  다중 사용자 지원 그리기 놀이.</dd>
 <dt>
  <a class="external" href="http://www.abrahamjoffe.com.au/ben/canvascape/">Canvascape</a></dt>
 <dd>
  3D 어드벤처 게임 (1인칭 슈팅).</dd>
 <dt>
  <a href="/en-US/docs/Web/Guide/HTML/A_basic_ray-caster" title="/en-US/docs/Web/Guide/HTML/A_basic_ray-caster">A basic ray-caster</a></dt>
 <dd>
  키보드를 사용한 애니메이션 제어 방법에 대한 좋은 예제.</dd>
 <dt>
  <a class="external" href="http://andrewwooldridge.com/canvas/canvasgame001/canvasgame002.html">canvas adventure</a></dt>
 <dd>
  키보드 제어를 사용하는 또다른 좋은 예제.</dd>
 <dt>
  <a class="external" href="http://www.blobsallad.se/">An interactive Blob</a></dt>
 <dd>
  물방울 갖고 놀기.</dd>
 <dt>
  <a class="external" href="http://arapehlivanian.com/wp-content/uploads/2007/02/canvas.html">Flying through a starfield</a></dt>
 <dd>
  별, 동그라미, 네모가 떠다니는 우주를 누벼라.</dd>
 <dt>
  <a class="external" href="http://igrapher.com/" title="http://igrapher.com/">iGrapher</a></dt>
 <dd>
  주식 시장 자료 차트 예제.</dd>
</dl>
<h2 id="이것도_보세요">이것도 보세요</h2>
<ul>
 <li><a href="/en-US/docs/JavaScript/Timers" title="/en-US/docs/JavaScript/Timers">JavaScript timers</a></li>
 <li><a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework"><code>setInterval</code> – A little framework</a></li>
 <li><a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">JavaScript Daemons Management</a></li>
 <li><a href="/en-US/docs/DOM/HTMLCanvasElement" title="/en-US/docs/DOM/HTMLCanvasElement">HTMLCanvasElement</a></li>
</ul>
<p>{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Compositing", "Web/Guide/HTML/Canvas_tutorial/Optimizing_canvas")}}</p>