[HTML/Canvas] 공 움직이기 애니메이션(basic ver)

공 움직이기 애니메이션(basic ver)

mdn의 캔버스 튜토리얼 따라하기

참고 : 캔버스 튜토리얼



1. 공 그리기

HTML

<canvas id="canvas" width="600" height="300"></canvas>

JS

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

const ball = {
  // 초기 위치
  x: 100,
  y: 100,
  // 속도
  vx: 5,
  vy: 1,
  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();
  },
};

ball.draw();



2. 속도 추가

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;
  raf = window.requestAnimationFrame(draw);
}

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

canvas.addEventListener("mouseout", (e) => {
  window.cancelAnimationFrame(raf);
});

ball.draw();



3. 경계

경계 추가 코드

🔺y축을 예시로 충돌 검사하는 방법


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.radius || // 바닥 충돌 감지
    ball.y + ball.vy < ball.radius // 천장 충돌 감지
  ) {
    ball.vy = -ball.vy; // 수직 방향 반전
  }
  if(
    ball.x + ball.vx > canvas.width - ball.radius ||
    ball.x + ball.vx < ball.radius
  ) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}



4. 가속

  ball.vy *= 0.99; // 수직 속고 감속, 부드러운 움직임
  ball.vy += 0.25; // 수직 속도에 외력 추가



5. 후행효과

ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);


🔺불투명도 0일 때


🔺불투명도 30일 때

불투명도가 점점 올라가면서 잔상과 같은 효과가 남.



6. 마우스 컨트롤 추가(최종 코드)

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf; // 애니메이션 제어
let running = false; // 공 애니메이션 진행 여부

const ball = {
  // 초기 위치
  x: 100,
  y: 100,
  // 속도
  vx: 5,
  vy: 1,
  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 clear() {
    // 후행효과(잔상)
    ctx.fillStyle = "rgb(255 255 255 / 30%)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
}

function draw() {
  // 프레임 지우기
  //ctx.clearRect(0, 0, canvas.width, canvas.height);
  clear();

  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.radius || // 바닥 충돌 감지
    ball.y + ball.vy < ball.radius // 천장 충돌 감지
  ) {
    ball.vy = -ball.vy; // 수직 방향 반전
  }
  if(
    ball.x + ball.vx > canvas.width - ball.radius ||
    ball.x + ball.vx < ball.radius
  ) {
    ball.vx = -ball.vx;
  }

  raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener("mousemove", (e) => {
  if(!running) {
    clear();
    // 캔버스 위치에 따라 오차가 남 엘리먼트 밖 여백 제거한 후 위치로 세팅
    ball.x = e.clientX - canvas.getBoundingClientRect().left;
    ball.y = e.clientY - canvas.getBoundingClientRect().top;
    ball.draw();
  }
});

canvas.addEventListener("click", (e) => {
  if(!running) {
    raf = window.requestAnimationFrame(draw);
    running = true;
  }
});

// canvas.addEventListener("mouseover", (e) => {
//   raf = window.requestAnimationFrame(draw);
// });

canvas.addEventListener("mouseout", (e) => {
  window.cancelAnimationFrame(raf); // 애니메이션 중지
  running = false;
});

ball.draw();