Vue.js로 스프라이트 시트 동작 시키기 (2) - 불러오기

Dev Smile·2024년 8월 14일
2

앞선 스프라이트 시트 설명 글에 이어서, 이번 글에서는 Vue.js를 사용해 스프라이트 시트를 재생하는 코드를 구현하는 방법을 알아보겠습니다.

1. vue.js 프로젝트 생성

  • yarn을 통한 vue create 사용
    yarn create vue
  • 위 안내를 따라서 라이브러리 설치 및 프로젝트 실행
    yarn 
    yarn format 
    yarn dev

2. 스프라이트 시트 준비

  • 스프라이트 시트 이미지를 준비해야 합니다. 예를 들어, 캐릭터가 걷는 애니메이션을 표현한 스프라이트 시트를 사용한다고 가정합니다. 이 시트는 여러 개의 프레임으로 구성되어 있고, 각 프레임은 캐릭터의 걷는 동작을 나타냅니다.
  • 이 글에서 스프라이트 시트를 동작 시켜보기 위해 사용할 스프라이트는 itch.io에서 Immunity님이 무료로 제공하고 있는 pixel top down character 캐릭터를 사용하도록 하겠습니다.
  • 위 링크에서 압축 파일을 다운로드 받아 압축 해제한 후 "Girl-Sheet.png" 파일을 assets 폴더 안에 넣어둡니다.

3. SpriteAnimator 컴포넌트 작성

  • src/components/SpriteAnimator.vue 파일을 생성합니다.
  • 이 컴포넌트는 애니메이션 스프라이트 시트를 화면에 렌더링하고 애니메이션을 수행하는 컴포넌트입니다.
<template>
  <!-- spriteStyle을 사용하여 div 요소를 렌더링, 이 div는 애니메이션 스프라이트 시트가 표시될 영역입니다. -->
  <div :style="spriteStyle"></div>
</template>

<script>
export default {
  // 컴포넌트의 속성(props)을 정의
  props: {
    frameWidth: {
      type: Number,
      required: true // 각 프레임의 너비
    },
    frameHeight: {
      type: Number,
      required: true // 각 프레임의 높이
    },
    totalFrames: {
      type: Number,
      required: true // 스프라이트 시트에서의 전체 프레임 수
    },
    animationSpeed: {
      type: Number,
      default: 100 // 애니메이션의 속도(밀리초 단위)이며, 기본값은 100ms입니다.
    },
    spriteSheet: {
      type: String,
      required: true // 스프라이트 시트 이미지
    },
    scale: {
      type: Number,
      default: 1 // 이미지 확대/축소 배율로, 기본값은 1(원본 크기)입니다.
    }
  },
  data() {
    // 컴포넌트의 반응형 데이터를 정의합니다.
    return {
      currentFrame: 0 // 현재 애니메이션에서 보여지는 프레임의 인덱스
    }
  },
  computed: {
    // 계산된 속성으로, div의 스타일을 동적으로 설정합니다.
    spriteStyle() {
      return {
        width: `${this.frameWidth}px`, // div의 너비를 프레임 너비로 설정
        height: `${this.frameHeight}px`, // div의 높이를 프레임 높이로 설정
        backgroundImage: `url(${this.spriteSheet})`, // 스프라이트 시트 이미지를 배경으로 설정
        backgroundPosition: `-${this.currentFrame * this.frameWidth}px 0px`, // 현재 프레임에 따라 배경 이미지의 위치를 조정
        backgroundRepeat: 'no-repeat', // 배경 이미지가 반복되지 않도록 설정
        transform: `scale(${this.scale})`, // 이미지의 크기를 설정된 scale 값으로 조정
        transformOrigin: 'top left' // 변환의 기준점을 왼쪽 상단으로 설정
      }
    }
  },
  mounted() {
    // 컴포넌트가 DOM에 마운트된 후 애니메이션을 시작합니다.
    this.startAnimation()
  },
  beforeUnmount() {
    // 컴포넌트가 DOM에서 제거되기 전에 애니메이션을 중지합니다.
    this.stopAnimation()
  },
  methods: {
    // 애니메이션을 시작하는 메소드
    startAnimation() {
      // 일정 시간 간격마다 currentFrame을 증가시킴으로써 애니메이션 효과를 구현
      this.animationInterval = setInterval(() => {
        this.currentFrame = (this.currentFrame + 1) % this.totalFrames
        // currentFrame이 totalFrames를 넘지 않도록 모듈러 연산 사용
      }, this.animationSpeed)
    },
    // 애니메이션을 중지하는 메소드
    stopAnimation() {
      // 애니메이션을 중지하기 위해 setInterval을 해제
      clearInterval(this.animationInterval)
    }
  }
}
</script>

<style scoped>
/* div의 스타일을 정의하며, 오버플로우된 콘텐츠가 보이지 않도록 숨깁니다. */
div {
  overflow: hidden;
}
</style>

3.1. SpriteAnimator.vue 코드 상세 설명

3.1.1. Props (속성)

  • frameWidth, frameHeight, totalFrames, spriteSheet는 스프라이트 애니메이션을 구성하는 필수 요소들입니다. 프레임의 크기, 총 프레임 수, 그리고 스프라이트 시트 이미지를 지정합니다.
  • animationSpeed와 scale은 옵션으로 설정할 수 있으며, 각각 애니메이션 속도와 스프라이트 시트의 크기를 조절합니다.

3.1.2. Data

  • currentFrame은 현재 표시되고 있는 프레임의 인덱스를 저장합니다. 이 값은 시간이 지남에 따라 업데이트되어 애니메이션을 생성합니다.

3.1.3. Computed (계산된 속성)

  • spriteStyle은 div 요소에 적용될 스타일을 계산합니다. 스프라이트 시트에서 적절한 프레임을 선택하기 위해 backgroundPosition 속성을 사용하고, transform을 통해 이미지를 확대/축소합니다.

3.1.4. Lifecycle Hooks

  • mounted()에서 startAnimation()을 호출하여 컴포넌트가 DOM에 마운트되자마자 애니메이션이 시작됩니다.
  • beforeUnmount()에서는 stopAnimation()을 호출하여 컴포넌트가 DOM에서 제거되기 전에 애니메이션을 멈춥니다.

3.1.5. Methods

  • startAnimation() 메서드는 setInterval을 사용하여 주기적으로 currentFrame을 업데이트함으로써 애니메이션을 생성합니다.
  • stopAnimation() 메서드는 clearInterval을 사용하여 애니메이션을 중지합니다.

3.1.6. Style

  • div 요소는 overflow: hidden; 속성을 통해 프레임의 크기를 넘는 이미지를 숨깁니다. 이는 애니메이션이 프레임 크기를 초과하지 않도록 보장합니다.

4. 컴포넌트 사용

  • 이제 App.vue 파일에서 SpriteAnimator.vue 컴포넌트를 불러와 사용합니다.
<template>
  <!-- 최상위 div 요소로, 애플리케이션의 루트 요소입니다. -->
  <div id="app">
    <!-- SpriteAnimator 컴포넌트를 호출, 애니메이션 속성들을 전달합니다. -->
    <SpriteAnimator
      :frameWidth="24"         
      :frameHeight="24"        
      :totalFrames="48"        
      :animationSpeed="150"    
      :spriteSheet="spriteSheetPath" 
      :scale="2"               
    />
  </div>
</template>

<script>
// SpriteAnimator 컴포넌트를 불러옵니다.
import SpriteAnimator from './components/SpriteAnimator.vue'
// 애니메이션에 사용할 스프라이트 시트 이미지를 불러옵니다.
import girlSheet from '@/assets/Girl-Sheet.png'

export default {
  name: 'App', // 이 컴포넌트의 이름을 'App'으로 설정합니다.
  components: {
    // SpriteAnimator 컴포넌트를 등록하여 이 컴포넌트 내에서 사용 가능하게 합니다.
    SpriteAnimator
  },
  data() {
    // 컴포넌트의 데이터 속성으로, 스프라이트 시트의 경로를 저장합니다.
    return {
      spriteSheetPath: girlSheet // 스프라이트 시트 이미지 경로를 지정
    }
  }
}
</script>

4.1. App.vue 코드 상세 설명

4.1.1. Template

  • div 요소는 애플리케이션의 루트 요소로 id="app"을 가지고 있습니다. 이 요소 안에 SpriteAnimator 컴포넌트가 포함되어 있습니다.
  • SpriteAnimator는 이전에 정의한 애니메이션 컴포넌트로, 여기에서 다양한 속성을 통해 애니메이션을 정의하고 있습니다.
    • frameWidth: 각 프레임의 너비를 24px로 설정합니다.
    • frameHeight: 각 프레임의 높이를 24px로 설정합니다.
    • totalFrames: 스프라이트 시트에서 사용할 총 프레임 수를 48로 설정합니다.
    • animationSpeed: 애니메이션의 속도를 150ms로 설정하여 프레임 간 전환 속도를 조절합니다.
    • spriteSheet: 사용할 스프라이트 시트 이미지를 spriteSheetPath 데이터 속성에서 가져옵니다.
    • scale: 스프라이트 시트를 2배 확대하여 표시합니다.

4.1.2. Script

  • SpriteAnimator 컴포넌트를 불러와서 애플리케이션에서 사용할 수 있도록 등록합니다.
  • girlSheet는 스프라이트 시트 이미지 파일을 @/assets/Girl-Sheet.png 경로에서 불러옵니다. 이 파일은 Webpack에 의해 번들링된 이미지입니다.
  • data 함수는 컴포넌트에서 사용할 데이터를 반환합니다. 여기서 spriteSheetPath는 girlSheet 이미지를 가리키며, 이 경로는 SpriteAnimator 컴포넌트에 전달됩니다.

5. 실행 결과

  • 실행하면 아래 사진과 같이 동작을 볼 수 있습니다.
  • 스프라이트 시트의 모든 그림을 순서대로 한 프레임씩 보여주어 캐릭터가 움직이는 것처럼 보입니다.
  • 다음 글에서는 유저의 입력에 따라 캐릭터가 해당 방향을 향하는 기능을 구현해보도록 하겠습니다.

2개의 댓글

comment-user-thumbnail
2024년 8월 22일

흥미롭네요.. 한번해봐야지

1개의 답글

관련 채용 정보