Vue.js로 스프라이트 시트 동작 시키기 (4) - 캐릭터 위치 이동

Dev Smile·2024년 8월 14일
1

앞선 방향키로 원하는 프레임을 표시하는 것에 더해서 캐릭터를 원하는 방향으로 이동시키는 방법을 알아보겠습니다.

1. SpriteAnimator 컴포넌트 수정

  • src/components/SpriteAnimator.vue 파일을 수정합니다.
<template>
  <div :style="spriteStyle" class="sprite"></div>
</template>

<script>
export default {
  props: {
    frameWidth: {
      type: Number,
      required: true
    },
    frameHeight: {
      type: Number,
      required: true
    },
    animationSpeed: {
      type: Number,
      default: 100
    },
    spriteSheet: {
      type: String,
      required: true
    },
    scale: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      currentFrame: 0,
      direction: 2, // 0: Up, 1: Right, 2: Down, 3: Left
      isMoving: false,
      x: 0, // 캐릭터의 x 좌표
      y: 0, // 캐릭터의 y 좌표
      moveSpeed: 2, // 캐릭터의 이동 속도
      frames: {
        idle: [
          [12, 13, 14, 15], // Up
          [8, 9, 10, 11], // Right
          [0, 1, 2, 3], // Down
          [4, 5, 6, 7] // Left
        ],
        move: [
          [34, 35, 36, 37, 38, 39], // Up
          [28, 29, 30, 31, 32, 33], // Right
          [16, 17, 18, 19, 20, 21], // Down
          [22, 23, 24, 25, 26, 27] // Left
        ],
        die: [40, 41, 42, 43]
      },
      pressedKeys: new Set() // 현재 눌린 키를 저장하는 Set
    }
  },
  computed: {
    spriteStyle() {
      return {
        width: `${this.frameWidth}px`,
        height: `${this.frameHeight}px`,
        backgroundImage: `url(${this.spriteSheet})`,
        backgroundPosition: `-${this.getCurrentAnimationFrame() * this.frameWidth}px -0px`,
        backgroundRepeat: 'no-repeat',
        transform: `scale(${this.scale})`, // 스프라이트의 크기를 조절
        transformOrigin: 'top left', // 변환 기준점 설정
        position: 'absolute',
        left: `${this.x}px`, // 캐릭터의 x 위치
        top: `${this.y}px` // 캐릭터의 y 위치
      }
    }
  },
  mounted() {
    this.startAnimation()
    window.addEventListener('keydown', this.handleKeydown)
    window.addEventListener('keyup', this.handleKeyup)
    this.updateMovement() // 움직임 업데이트 시작
  },
  beforeUnmount() {
    this.stopAnimation()
    window.removeEventListener('keydown', this.handleKeydown)
    window.removeEventListener('keyup', this.handleKeyup)
  },
  methods: {
    startAnimation() {
      this.animationInterval = setInterval(() => {
        if (this.isMoving) {
          this.currentFrame = (this.currentFrame + 1) % this.frames.move[this.direction].length
        } else {
          this.currentFrame = (this.currentFrame + 1) % this.frames.idle[this.direction].length
        }
      }, this.animationSpeed)
    },
    stopAnimation() {
      clearInterval(this.animationInterval)
    },
    getCurrentAnimationFrame() {
      if (this.isMoving) {
        return this.frames.move[this.direction][this.currentFrame]
      } else {
        return this.frames.idle[this.direction][this.currentFrame]
      }
    },
    handleKeydown(event) {
      this.pressedKeys.add(event.key)
      this.updateDirectionAndMovement()
    },
    handleKeyup(event) {
      this.pressedKeys.delete(event.key)
      this.updateDirectionAndMovement()
    },
    updateDirectionAndMovement() {
      // 현재 누른 키에 따라 방향과 이동 상태를 업데이트합니다.
      if (this.pressedKeys.size === 0) {
        this.isMoving = false
        return
      }

      this.isMoving = true
      if (this.pressedKeys.has('ArrowUp')) {
        this.direction = 0 // Up
      }
      if (this.pressedKeys.has('ArrowRight')) {
        this.direction = 1 // Right
      }
      if (this.pressedKeys.has('ArrowDown')) {
        this.direction = 2 // Down
      }
      if (this.pressedKeys.has('ArrowLeft')) {
        this.direction = 3 // Left
      }
    },
    moveCharacter() {
      // 캐릭터의 위치를 업데이트합니다.
      if (this.pressedKeys.has('ArrowUp')) {
        this.y -= this.moveSpeed
      }
      if (this.pressedKeys.has('ArrowRight')) {
        this.x += this.moveSpeed
      }
      if (this.pressedKeys.has('ArrowDown')) {
        this.y += this.moveSpeed
      }
      if (this.pressedKeys.has('ArrowLeft')) {
        this.x -= this.moveSpeed
      }
    },
    updateMovement() {
      // 움직임을 지속적으로 업데이트합니다.
      this.moveCharacter()
      requestAnimationFrame(this.updateMovement) // 다음 프레임에 updateMovement를 호출합니다.
    }
  }
}
</script>

<style scoped>
.sprite {
  overflow: hidden;
}
</style>

1.1. SpriteAnimator.vue 코드 상세 설명

1.1.1. Data

  • x와 y: 캐릭터의 현재 위치를 나타내는 좌표입니다.
  • moveSpeed: 캐릭터의 이동 속도를 나타냅니다.
  • pressedKeys: 현재 눌린 키를 저장하는 Set 객체입니다.

1.1.2. Methods

  • handleKeydown과 handleKeyup
    • 키보드 입력을 처리하여 pressedKeys를 업데이트하고, 이에 따라 캐릭터의 방향과 움직임을 업데이트합니다.
  • updateDirectionAndMovement
    • 눌린 키에 따라 캐릭터의 방향을 설정하고, isMoving 상태를 업데이트합니다.
  • moveCharacter
    • 방향에 따라 캐릭터의 위치를 업데이트합니다.
  • updateMovement
    • moveCharacter를 호출하고, requestAnimationFrame을 통해 반복적으로 updateMovement를 호출합니다.

2. 실행 결과

  • 실행하면 아래 사진과 같이 동작을 볼 수 있습니다.
  • 페이지 위에서 캐릭터가 입력하는 방향키에 따라 움직입니다.
  • 다음 링크에서 테스트 해볼 수 있습니다. : https://vue-demo-vert.vercel.app/sprite

0개의 댓글

관련 채용 정보