본문 바로가기
  • search_ _ _ _
  • search_ _ _ _
  • search_ _ _ _
JavaScript &jQuery

[JavaScript] Sprite Sheets 애니메이션

by 오늘의갈비찜 2024. 6. 14.
728x90

1. html

- canvas 태그 생성

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>canvas test</title>
    </head>
    <body>
        <canvas></canvas>
    </body>
</html>

 

 

2. css

body{
    position: relative;
    height: 100vh;
}

canvas {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    background-color:rgb(248 224 217);
}

 

3. javascript

 

1). 이미지 호출

 

- drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

매개변수(sx, sy)는 스프라이트 시트(소스)의 시작 위치,

(dx, dy)는 캔버스(대상)의 시작 위치며 기본적으로 왼쪽 상단이 (0, 0)에서 시작하여 오른쪽과 아래쪽으로 양수로 이동하는 그리드입니다.

 

"너비" 및 "높이" 매개변수( sWidth, sHeight)는  스프라이트 시트의 너비와 높이를 

(dWidth및 dHeight)는 캔버스의 너비와 높이를 나타냅니다. 캔버스의 영역만큼 이미지를 가득 채워 확대시킵니다.

 

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

canvas.width = 500;
canvas.height = 400;

let img = new Image();  //객체 생성
img.src = 'https://opengameart.org/sites/default/files/Green-Cap-Character-16x18.png';
img.onload = function() {
  init();
};


function init() {
  // future animation code goes here

  ctx.drawImage(img, 0, 0, 16, 18, 20, 10, 16, 18);
  // 소스이미지 안에 이미지는 16x18 출력 
  // 소스이미지에서 x, y, width, height , 캔버스 x, y, width, height 
}

 

 

2). 이미지 호출

 

- drawImage( ) 변수값

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

canvas.width = 500;
canvas.height = 400;

let img = new Image();  //객체 생성
img.src = 'https://opengameart.org/sites/default/files/Green-Cap-Character-16x18.png';
img.onload = function() {
  init();
};


const scale = 2; //확대
const width = 16; //이미지 너비
const height = 18; //이미지 높이
const scaledWidth = scale * width;
const scaledHeight = scale * height;

function init() {
  ctx.drawImage(img, 
                0, 0, width, height, 20, 10, scaledWidth, scaledHeight);
              //0 , 0 , 16, 18, 20, 10, 32, 36
  ctx.drawImage(img, 
                width, 0, width, height, scaledWidth + 20, 10, scaledWidth, scaledHeight);
              //16 , 0 , 16, 18, 32+20 , 10, 32, 36
  ctx.drawImage(img, 
                width * 2, 0, width, height, (scaledWidth * 2) + 20 , 10, scaledWidth, scaledHeight);
              //16*2 , 0 , 16, 18, (32*2)+20, 10, 32, 36
}

3). 이미지 호출

 

-  drawFrame( )

스프라이트 시트 수학을 처리하므로 프레임 번호만 전달하면 됩니다.

 

let img = new Image();  //객체 생성
img.src = 'https://opengameart.org/sites/default/files/Green-Cap-Character-16x18.png';
img.onload = function() {
  init();
};


const scale = 2; //확대
const width = 16; //이미지 너비
const height = 18; //이미지 높이
const scaledWidth = scale * width;
const scaledHeight = scale * height;

const paddingLeft = 20;
const paddingTop = 10;


function drawFrame(frameX, frameY, canvasX, canvasY) {
  ctx.drawImage(img,
                frameX * width, frameY * height, width, height,
  
                canvasX, canvasY, scaledWidth, scaledHeight);
}

function init() {
  drawFrame(0, 0, paddingLeft, paddingTop);
  drawFrame(1, 0, scaledWidth+paddingLeft, paddingTop);
  drawFrame(0, 0, (scaledWidth * 2)+paddingLeft, paddingTop);
  drawFrame(2, 0, (scaledWidth * 3)+paddingLeft, paddingTop);
}

4). 애니메이션

 

- equestAnimationFrame( ) 애니메이션 루프를 생성하기 위해 인수로 전달하는 재귀함수 입니다.

                                            초당 60프레임으로 그려집니다.

 

function step() {


  // do something
  window.requestAnimationFrame(step);
}

 

- clearRect(x, y, 너비, 높이)  캔버스에서 지정된 픽셀을 지웁니다. 

   (노출되는 이미지 외의 이미지는 지우기 위해)

function drawFrame(frameX, frameY, canvasX, canvasY) {
  ctx.drawImage(img,
                frameX * width, frameY * height, width, height,
                canvasX, canvasY, scaledWidth, scaledHeight);
}

const cycleLoop = [0, 1, 0, 2];  //노출 이미지
let i = 0;                       //이미지 index

function step() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  //선택 이외의 이미지 삭제

  drawFrame(cycleLoop[i], 0, paddingLeft, paddingTop); //이미지 호출

  i++;
  if (i >= cycleLoop.length) {  //이미지 반복
    i = 0;
  }

  window.requestAnimationFrame(step);
}

 

 

4). 애니메이션_반복

 

- equestAnimationFrame( ) 초당 60프레임 -> 초당 15프레임

                                            초당 0~15 프레임이 끝나야 새로운 이미지를 그릴 수 있습니다.

 

const cycleLoop = [0, 1, 0, 2];  
let i = 0;                       
let frameCount = 0;              //프레임 초기화

function step() {
  frameCount++;
  if (frameCount < 15) {  //초당 0 ~ 15프레임
    window.requestAnimationFrame(step);
    return;
  }
  frameCount = 0;  //프레임 초기화

  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawFrame(cycleLoop[i], 0, paddingLeft, paddingTop);

  i++;
  if (i >= cycleLoop.length) {
    i = 0;
  }

  window.requestAnimationFrame(step);
}

 

 

5). 애니메이션_반복 전환

 

-이미지 방향 전환을 위한 변수를 생성합니다.

const cycleLoop = [0, 1, 0, 2];  
let i = 0;           
let frameCount = 0; 
let currentDirection = 0;   //이미지 방향

function step() {
  frameCount++;
  if (frameCount < 15) {
    window.requestAnimationFrame(step);
    return;
  }

  frameCount = 0;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawFrame(cycleLoop[i], currentDirection, paddingLeft, paddingTop);  //frameY = currentDirection

  i++;
  if (i >= cycleLoop.length) {
    i = 0;
    currentDirection++;  
  }

  if (currentDirection >= 4) {
    currentDirection = 0;  
  }

  window.requestAnimationFrame(step);
}

function init() {
  window.requestAnimationFrame(step);
}

 

 

 

 

 

 

See the Pen sprite sheets animation_1 by gaae (@gaae) on CodePen.

 

 

 

 

 

 

 

 

 

 

 

 

 

참고: 

https://dev.to/martyhimmel/animating-sprite-sheets-with-javascript-ag3

 

Animating Sprite Sheets With JavaScript

Learn how to animate a character on a sprite sheet using HTML5's canvas and JavaScript.

dev.to

 

728x90