[2022.05.12] Canvas API - 캔버스 애니메이션 적용하기

REASON·2022년 5월 11일
0

STUDY

목록 보기
43/127
post-thumbnail

지난번에 작성한 캔버스 관련 포스트
Canvas API 개념 & 기본 사용방법
Canvas API 선과 원 그리기

목차

  1. 캔버스에서 애니메이션 구현하기 (requestAnimationFrame)
    • 원이 수평으로 움직이도록 만들기
    • setInterval 사용해보기
    • setInterval과 비교
    • requestAnimationFrame으로 타이밍 조절하기

canvas 애니메이션 만들기

애니메이션은 반복해서 보여줘야 하기 때문에 그리고 지우고 살짝 이동시켜서 그리고 지우고를 반복하면 된다.

const canvas = document.querySelector('.canvas');
const context = canvas.getContext('2d');

function draw() {
  context.arc(10, 150, 10, 0, Math.PI * 2, false);
  context.fill();
}

draw();

먼저 사용한 예제 코드는 draw라는 함수를 만들어서 반지름 10짜리 원을 그리도록 했다. 이제 이 원이 움직이도록 코드를 작성해볼 것이다.

어떻게 반복 시킬까?

윈도우 전역객체가 가진 requestAnimationFrame() 메소드를 사용하여 기본적인 반복을 수행시킬 수 있다.
동작시킬 애니메이션을 알리고 다음 리페인트가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출시키는 메소드이다.

const canvas = document.querySelector('.canvas');
const context = canvas.getContext('2d');

function draw() {
  context.arc(10, 150, 10, 0, Math.PI * 2, false);
  context.fill();

  requestAnimationFrame(draw);
  // 반복적으로 그릴 함수 안에서 호출 (재귀함수)
}

draw();

// requestAnimationFrame(draw); // 여기서 호출하면 한번만 실행

반복하고자 하는 함수 안에서 requestAnimationFrame 메소드를 호출하면 된다. 파라미터에는 해당 함수 이름을 적어서 재귀 함수로 만들어주면 된다.

만약, 함수 안이 아닌 바깥에서 호출하는 경우엔 한번만 실행된다.

이제 애니메이션을 만들어주기 위해서는 원의 좌표를 바꿔서 반복시키면 될 것이다. 현재 위의 코드는 위치가 고정되어 있기 때문에 동일한 위치에 원을 계속 그리고 있을 것이다. (기본적으로 1/60초를 목표로 한다.)
원의 x축을 바꾸면 수평이동시킬 수 있을 것이다.

let xPos = 10;

function draw() {
  context.arc(xPos, 150, 10, 0, Math.PI * 2, false);
  context.fill();
  xPos += 3;

  requestAnimationFrame(draw);
}

draw();

x좌표를 변경해줄 변수를 선언하고 arc메소드 안의 x좌표 파라미터에 해당 변수를 넣어주었다.

1초에 약 60프레임만큼 xPos의 값이 3씩 증가되면서 위와 같은 형태로 애니메이션이 동작하게 된다.

그런데 공이 이동하는 애니메이션이 아닌 선이 연결되는 애니메이션이 되었다. 그 이유는 그리기만하고 지우지 않았기 때문이다.

원이 수평으로 움직이도록 만들기

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.beginPath();

  context.arc(xPos, 150, 10, 0, Math.PI * 2, false);
  context.fill();
  xPos += 3;

  requestAnimationFrame(draw);)
}

함수안에서 clearRect 메소드를 사용하여 전체 캔버스를 지워주고 원을 그리도록 작성하면 된다.
여기서 beginPath가 작성되어있지 않다면, 앞서 선이 연결되는 것처럼 동일하게 동작하니 주의!

setInterval로도 가능하다.

const canvas = document.querySelector('.canvas');
const context = canvas.getContext('2d');

let xPos = 10;

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.beginPath();

  context.arc(xPos, 150, 10, 0, Math.PI * 2, false);
  context.fill();
  xPos += 3;
}

setInterval(draw, 20);

setInterval을 사용해서 만든 애니메이션이다.
초당 몇번을 반복할지 정해줄 수 있다는 장점(컨트롤이 쉽다)이 있다.

그러면 setInterval이 더 좋은 것 아닌가?

기본적으로 기능은 그래보이지만, setInterval을 사용하지 않는 것은 requestAnimationFrame의 장점을 갖고 있지 않기 때문이다. requestAnimationFrame에 비해 버벅임 이슈라던가, 리페인트가 진행되기 전까지 기다려준다거나, 모바일 기기에서의 배터리 성능 등을 따져봤을 때 requestAnimtaionFrame이 캔버스 애니메이션에 있어서 장점이 더 큰 편이다.
고성능 애니메이션을 다루지 않는다면 setInterval을 사용해도 되긴 할 것이다.

setInterval처럼 반복되는 속도나 타이밍을 조절하는 방법

const canvas = document.querySelector('.canvas');
const context = canvas.getContext('2d');

let xPos = 10;
let count = 0;

function draw() {
  if (count % 30 === 0) { // 약 0.5초에 한번 실행된다.
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();

    context.arc(xPos, 150, 10, 0, Math.PI * 2, false);
    context.fill();
    xPos += 3;
  }

  count++;

  requestAnimationFrame(draw);
}

draw();

count라는 변수를 선언하고 매 프레임마다 카운트를 1씩 증가시킨다. 카운트를 30으로 나눴을 때 나머지가 0인 경우에만 if문이 충족되어 해당 코드가 실행된다.
위 코드대로 진행하면 약 0.5초에 한번씩 원이 수평으로 이동하는 것처럼 보여진다.

즉, 나머지 연산자를 사용해 애니메이션 타이밍을 조정할 수 있는 것이다.


참고 자료
1분 코딩 - HTML5 Canvas 캔버스 라이브 강좌 #1
MDN window.requestAnimationFrame()

0개의 댓글