이 글에서는 2D 캐릭터 애니메이션을 시작할 때 비교하기 쉬운 두 방식, 프레임 교체와 간단한 코드 변형을 살펴본다. 모든 애니메이션 기법을 두 가지로 분류한다는 뜻은 아니다.

하나는 여러 장의 그림을 빠르게 교체하는 Sprite Sheet 방식이고, 다른 하나는 코드로 움직임과 변형을 계산하는 Procedural Animation 방식이다. 여기서는 한 장의 이미지에 적용하는 간단한 변형을 예로 든다.

둘 다 많이 쓰이고, 목적도 조금 다르다.


1. Sprite Sheet Animation

가장 전통적인 2D 캐릭터 애니메이션 방식이다.

걷기 동작이라면 캐릭터의 자세를 여러 장 준비한다.

걷기 애니메이션은 1~6번 프레임을 순서대로 반복 재생하는 방식이다.

이 프레임들을 일정한 속도로 반복하면 캐릭터가 걷는 것처럼 보인다.

보통 상태별로 이런 프레임을 만든다.

  • Idle
  • Walk
  • Run
  • Jump
  • Attack
  • Hit
  • Dead

Phaser 같은 2D 게임 엔진은 이런 frame-based animation을 기본으로 지원한다. 공식 문서에서도 Sprite Sheet나 Texture Atlas의 프레임을 순서대로 재생하는 방식을 기본 애니메이션 방식으로 설명하고 있다.

예를 들어 Phaser에서는 다음처럼 애니메이션을 정의할 수 있다.

this.anims.create({
  key: 'walk',
  frames: this.anims.generateFrameNumbers('player', {
    start: 0,
    end: 5
  }),
  frameRate: 10,
  repeat: -1
});

이후 캐릭터가 움직일 때:

player.play('walk', true);

멈추면:

player.play('idle', true);

처럼 상태에 따라 애니메이션을 바꿀 수 있다.

구조는 단순하다.

Player State에 맞는 프레임 묶음을 선택한다.

  • Idle: idle frames
  • Walk: walk frames
  • Jump: jump frames
  • Attack: attack frames

장점은 캐릭터의 팔, 다리, 표정까지 원하는 대로 표현할 수 있다는 점이다. 반대로 프레임을 직접 만들어야 하므로 아트 작업량이 늘어난다.


2. Procedural Animation

반대로 캐릭터 이미지 한 장만 있어도 어느 정도 움직임을 만들 수 있다.

예를 들어:

  • Scale
  • Rotate
  • Flip
  • Tween

같은 변형을 코드로 적용하는 방식이다.

왼쪽으로 이동할 때 캐릭터를 뒤집는다면:

player.setFlipX(true);

걷는 느낌을 내기 위해 몸을 살짝 눌렀다 늘릴 수도 있다.

const bounce = Math.sin(time * 0.02) * 0.04;
player.setScale(1 + bounce, 1 - bounce);

점프할 때는 세로로 늘리고:

player.setScale(0.85, 1.15);

착지할 때는 반대로 눌러줄 수 있다.

player.setScale(1.15, 0.85);

이런 표현은 애니메이션에서 흔히 말하는 Squash & Stretch와 비슷하다.

Phaser의 Tween을 이용하면 공격, 착지, 피격 같은 짧은 움직임도 쉽게 만들 수 있다.

this.tweens.add({
  targets: player,
  scaleX: 1.2,
  scaleY: 0.85,
  duration: 80,
  yoyo: true
});

장점은 별도의 프레임 이미지가 없어도 빠르게 움직임을 만들 수 있다는 점이다.

특히 프로토타입이나 단순한 캐릭터에는 효과적이다.


Sprite Sheet vs Procedural Animation

방식 장점 단점
Sprite Sheet 자세한 동작 표현, 자연스러운 걷기/공격 프레임 제작 필요
Procedural Animation 구현 빠름, 이미지 한 장으로 가능 세밀한 팔·다리 동작 표현이 어려움

둘 중 하나만 선택할 필요는 없다.

실제로는 둘을 같이 쓰는 것이 자연스럽다.

flowchart TD
    S["Sprite Sheet"] --> F["Walk / Run / Attack / Jump 프레임"]
    P["Procedural Animation"] --> E["착지 Squash / 피격 흔들림 / 공격 Scale"]
    P --> V["Camera Shake / 먼지 / Slash Effect"]
    F --> R["최종 캐릭터 연출"]
    E --> R
    V --> R

즉 캐릭터의 큰 움직임은 Sprite Sheet로 만들고, 게임의 타격감이나 생동감은 Procedural Animation으로 보완하는 방식이다.


Phaser에서 같이 사용한다면

Phaser에서는 Sprite가 frame animation을 지원하고, 동시에 Tween, Scale, Rotation, Tint 같은 속성도 적용할 수 있다.

그래서 이런 구조를 만들기 좋다.

flowchart TD
    N0["Input"]
    N1["Player State"]
    N2["Sprite Animation"]
    N3["Physics"]
    N4["Tween / Effect"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4

예를 들어 이동하면:

player.play('walk', true);

점프하면:

player.play('jump');

동시에 점프 순간에:

this.tweens.add({
  targets: player,
  scaleX: 0.9,
  scaleY: 1.1,
  duration: 80,
  yoyo: true
});

같은 추가 효과를 줄 수 있다.

이렇게 하면 Sprite Sheet만 사용할 때보다 훨씬 생동감 있는 움직임을 만들 수 있다.


뼈대 애니메이션이라는 선택지도 있다

Spine 같은 도구는 몸통·팔·다리 이미지를 뼈대에 연결하고 관절을 움직인다. 프레임별 완성 그림을 모두 그리지 않아도 자세를 바꿀 수 있으며 Phaser용 runtime도 제공된다.

방식 준비할 자산 선택 기준
프레임 애니메이션 자세별 그림, sprite sheet 또는 atlas 프레임마다 독특한 실루엣·표현이 중요할 때
뼈대 애니메이션 분리된 파츠, 리깅·애니메이션 데이터 관절 움직임과 파츠 교체를 재사용할 때
절차적 애니메이션 이미지/파츠/뼈대와 계산 로직 속도·지형·입력에 반응하는 움직임이 필요할 때

절차적 애니메이션은 scale tween에 한정되지 않는다. 뼈대나 IK와 조합할 수도 있다. Spine을 선택한다면 도구 라이선스와 runtime 버전 호환성을 먼저 확인한다.

예제를 연결할 때 주의할 점

위 코드는 독립 실행 게임이 아닌 핵심 API 예시다. 실제 프로젝트에는 sprite sheet 로딩 시 frame 크기, idle/jump 애니메이션 정의, 상태 전환 처리가 필요하다. update에서 매 프레임 scale을 쓰면서 같은 속성에 tween을 걸면 서로 덮어쓸 수 있으므로 상태별로 변형을 한 곳에서 관리한다. 원래 scale이 1이 아니라면 복귀 기준도 원래 값으로 둔다.

정리

2D 캐릭터 애니메이션을 시작할 때는 이렇게 생각하면 쉽다.

  • 빠른 프로토타입: Procedural Animation
  • 프레임별 캐릭터 동작: Sprite Sheet
  • 동작에 타격감과 생동감 추가: Sprite Sheet + Procedural Animation

처음에는 한 장짜리 캐릭터에 Flip, Scale, Tween만 적용해도 충분히 움직이는 느낌을 만들 수 있다.

걷기, 달리기, 공격처럼 팔다리의 자세가 바뀌는 동작은 프레임 애니메이션이나 뼈대 애니메이션으로 표현할 수 있다. Sprite Sheet가 반드시 필요한 것은 아니다.

이 예제에서는 프레임 동작을 Sprite Sheet, 보조 연출을 Procedural Animation, 이동과 충돌을 2D Physics가 담당하도록 역할을 나눈다.


참고