컨텐츠 검색
[UE5 BP] _#11. 애니메이션 블루프린트로 캐릭터 움직임 구현하기 – 블루프린트 직접 제어 (X) 스테이트 머신 기반 (O)

2025. 11. 28. 21:53Unreal Engine/개념

1. 애니메이션 블루프린트와 블렌드 스페이스의 적용

  • “이동만 되는 마네킹” → “속도에 따라 자연스럽게 Idle ↔ Run 하는 캐릭터”

1.1. 🧩 첫 번째 문제 상황 — 움직이기만 하고 애니메이션이 없던 상태

초기 구현된 캐릭터는 이동·점프 같은 게임플레이 로직은 작동했지만,
실제 움직임을 보여주는 시각적인 애니메이션이 전혀 없는 상태였다.

 

결과적으로 캐릭터는 뛰는 것이 아니라, 그냥 “캡슐이 미끄러지는 것 같은 느낌”을 주어 몰입감이 떨어진다.

또한 지금 내가 “서 있는지, 걷는지, 뛰는지, 점프 중인지”를 시각적으로 구분할 수 없다는 문제가 있었다.


💭 블루프린트 클래스만으로도 애니메이션은 적용 가능하다

① Animation Mode: Use Animation Asset

Character BP → Skeletal Mesh 컴포넌트 선택하여 Animation Mode를 Use Animation Asset으로 변경한 다음,

Anim to Play에 Run 애니메이션 시퀀스를 지정하면 해당 애니메이션이 계속 반복 재생된다.

하지만 이 방식은 캐릭터가 멈췄는데도 뛰거나, 애니메이션 시작/정지 타이밍이 실제 움직임과 따로 놀아 자연스러운 표현이 어렵다.




② 블루프린트에서 애니메이션 노드 직접 호출

또 다른 방법으로는 Event Graph에서 이동 키 입력 시 Play Animation(달리기), 키에서 손 떼면 Play Animation(Idle)

이런 식으로 입력 이벤트 → 애니메이션 전환도 가능하다.

 

하지만 이 경우에도 Idle ↔ Run 사이에 블렌딩(중간 동작)이 없기 때문에 자세가 “탁” 바뀌는 느낌이 강하다.

속도 변화(0 → 200 → 600…)를 반영해서 자연스럽게 바뀌는 구조가 아니라

조건문으로 애니메이션을 갈아끼우는 수준에 머무른다.

또한, 상태가 늘어날수록 if/Branch가 기하급수적으로 늘어나 “어떤 조건에서 어떤 애니가 나오는지”를 한눈에 보기 어려워진다.

 

결국 상태 변수 기반으로 부드러운 전환을 위해 애니메이션 블루프린트(ABP) 기반 구조로 구현하기로 했다.


1.2. 🎯 구현 목적

  • 캐릭터에 기본 Idle, Run 애니메이션을 적용한다.
  • 이동 속도에 따라 Idle ↔ Run이 자연스럽게 섞이도록(블렌딩) 만든다.
  • 애니메이션 관련 로직은 애니메이션 블루프린트(ABP) 안으로 모으고,
    캐릭터 블루프린트는 입력·이동 등 “게임플레이 로직”만 담당하게 한다.
  • 나중에 점프/낙하/착지/공격 등이 추가되어도
    전체 구조를 갈아엎지 않도록 확장 가능한 뼈대를 만든다.


1.3. 📌 개념 정리 — 애니메이션 블루프린트 & 블렌드 스페이스

✔ 애니메이션 블루프린트 (Animation Blueprint)

  • 특정 Skeleton에 연결되는 애니메이션 전용 블루프린트
  • 구성:
    • Event Graph: 캐릭터의 상태값(Speed, IsInAir 등)을 계산해 변수에 저장
    • Anim Graph: 그 변수들을 사용해 애니메이션 노드를 조합, 최종 포즈를 계산해 스켈레탈 메시에 전달
  • 한 마디로, 매 프레임 “이 캐릭터가 지금 어떤 포즈를 취해야 할지”를 결정하는 뇌.


✔ 블렌드 스페이스 (Blend Space)

  • 속도 같은 연속 값 기반으로 애니메이션을 섞는 에셋
  • Speed가 0이면 Idle, 속도가 높을수록 Run 쪽 포즈 비중 상승
  • Play Animation 방식보다 부드러운 전환을 자동 제공

1.4. 📌 애니메이션 블루프린트에서 속도 기반 Idle ↔ Run 구현

1) Blend Space 에셋 생성

  1. 캐릭터 Skeleton 기준으로 Blend Space 생성
  2. Axis Settings:
    • Y축: Speed (0 ~ 캐릭터 최대 이동 속도)
  3. 애니메이션 배치:
    • Speed 0: Idle 애니메이션
    • 최고 속도 근처: Run 애니메이션


2) Event Graph에서 Speed 변수 계산

  1. Event Blueprint Update Animation: 애니메이션이 갱신될 때마다 실행된다.
  2. Try Get Pawn Owner: 현재 이 ABP를 사용 중인 Pawn(캐릭터)를 가져온다.
  3. Pawn이 유효하다면:
    • Get Velocity: MovementComponent 또는 루트 컴포넌트 기준 속도를 FVector로 반환
    • Vector Length XY: X,Y 평면상의 속도 크기(수평 이동 속도)를 계산
    • 결과를 Speed(float 변수)에 저장

이제 Speed에는 항상 현재 이동 속도가 들어간다.

ABP_Character의 EventGraph


3) Anim Graph에서 Blend Space 적용

  1. Anim Graph에 BlendSpace Player 노드를 추가
  2. Blend Space의 Y 좌표 입력에 Speed 변수를 연결
  3. Blend Space 출력 포즈를 최종 Output Pose에 연결

이렇게 구성하면:

  • Speed == 0일 때는 Idle 포즈
  • Speed가 증가할수록 Run 포즈에 가까운 모션으로 자연스럽게 이어진다.

ABP_Character의 AnimGraph


1.5. ⚙️ 전체 처리 흐름

[플레이어 입력]
     ↓
[CharacterMovementComponent가 이동/속도 갱신]
     ↓
[AnimBlueprint Event Graph]
         - Try Get Pawn Owner
         - Get Velocity → Vector Length XY → Speed
     ↓
[Anim Graph]
         - Blend Space Player (Speed 기반 Idle/Run 블렌딩) → Output Pose
     ↓
[스켈레탈 메시에 최종 포즈 적용]

2. 스테이트 머신에 블렌드 스페이스의 적용

  • “수평 이동만 자연스러움” → “점프/낙하/착지까지 상태 기반으로 확장”

2.1. 🧩 두 번째 문제 상황 — ABP + 블렌드 스페이스만으로는 부족한 점

1단계 구조:

  • Anim Graph 안에 Blend Space 1개 → Output Pose
  • State Machine은 사용하지 않은 상태.

이 구조는:

  • 수평 이동(Idle ↔ Run) 처리를 위해서는 충분하지만,
  • 점프 / 낙하 / 착지 같은 상태 기반 애니메이션을 표현하기에는 부족하다.

❌ 한계

  1. “상태”를 표현하기 어렵다
    • Blend Space는 Speed 같은 연속적인 값에 따라 포즈를 섞는 데에 특화되어 있다.
    • “지금 점프 중인지, 떨어지는 중인지, 착지하는 중인지” 같은 이산적인 상태(State)를 표현하기에는 애매하다.
  2. 애니메이션이 늘어날수록 조건이 꼬인다
    • Idle/Run만 있을 때는 Blend Space 한 개면 충분하지만, Jump, FallLoop, Land, Attack, Hit, Death 등이 추가되면
      모든 것을 한 그래프 안에서 조건으로 처리하기 어렵다.
  3. 사람이 생각하는 방식과 그래프 구조가 어긋난다
    • 사람은 보통 아래와 같이 상태 단위(State)로 생각한다.
      • “지금은 Idle 상태야”
      • “지금은 Run 상태야”
      • “지금은 Jump 상태야”
    • 하지만 Blend Space 하나에만 의존하면 모든 것을 Speed나 몇 개의 값에 억지로 끼워 넣게 되어
      상태 전환 의도를 명확하게 드러내기 어렵다.

이 문제를 해결하기 위해 State Machine을 도입해 애니메이션을 상태 단위로 재구성했다.


2.2. 🎯 구현 목적

  • Idle / Run / Jump / Fall / Land를 각각 독립된 상태(State)로 분리한다.
  • 각 상태에서 어떤 애니메이션(또는 Blend Space)이 재생될지 정의한다.
  • 상태 간 이동 조건을 Transition Rule로 명확하게 표현한다.
  • 기존의 Speed 기반 Idle ↔ Run 구조는 유지하면서,
    그 위에 Jump/Fall/Land 상태를 추가해 확장한다.


2.3. 개념 정리 — State Machine, State, Transition, Conduit, State Alias

  • State Machine: 여러 State와 Transition, Conduit로 이루어진 그래프
    • 현재 상태를 기억하고, 조건에 따라 다른 상태로 전환한다.
  • State: Idle, Run, Jump 같은 하나의 애니메이션 그래프 단위
    • 상태가 활성화된 동안 그 상태의 애니메이션이 출력에 기여한다.
  • Transition Rule: 상태 간 이동 조건을 정의하는 Bool 그래프
    • 예: Speed > 0일 때 Idle → Run
  • Conduit: 복잡한 분기를 한 곳에서 처리할 수 있는 중간 노드

  • State Alias: 이미 정의된 State(또는 상태 묶음)를 다른 그래프에서 재사용하기 위한 별칭

2.4. 스테이트 머신 구성 및 점프 상태 추가

1) Anim Graph에 State Machine 추가

  • Anim Graph에서 New State Machine 노드를 만든다. 이름을 (Character State Machine으로 설정함.)
  • 이 State Machine의 출력을 최종 Output Pose에 연결한다.
AnimGraph
  └─ StateMachine "CharacterStateMachine"
        ↓
      Output Pose

AnimGraph




2) Idle / Run 상태 구성 (기존 구조를 State로 전환하기)

  • Idle State
    • Idle 애니메이션 시퀀스 재생
  • Run State
    • 기존에 만든 Idle/Run Blend Space 사용
    • Y 입력에 Speed 변수 연결
  • Transition Rule
    • Idle → Run : Speed > 0
    • Run → Idle : Speed <= 0

즉, 기존의 “Blend Space → Output Pose” 구조를

  • Idle State
  • Run State

두 개로 쪼개 State Machine 안으로 옮긴 것에 가깝다.

Character State Machine
Idle (state)
Run (state)
Idle to Run (rule)
Run to Idle (rule)







3) Event Graph에서 IsInAir 변수 계산

 

  • Try Get Pawn Owner → Movement Component → Is Falling
  • 결과를 IsInAir 변수에 저장
  • 이제 ABP는 Speed와 IsInAir 두 가지 상태를 모두 알 수 있다.

점프 상태를 나타내는 IsInAir bool 변수를 추가했다.

 


4) Jump / FallLoop / Land 상태 추가 및 트랜지션

  • Jump State: 점프 시작 애니메이션 재생
  • FallLoop State: 떨어지는 동안 재생되는 애니메이션
    • 높은 곳에서 오래 떨어질 수 있으므로 Loop 활성화
  • Land State: 땅에 착지하는 순간 재생되는 애니메이션

Transition Rule

  • Idle/Run → Jump: 점프 입력이 발생했을 때
  • Jump → FallLoop: Jump 애니메이션이 끝났을 때
    • 스테이트의 시퀀스 플레이어에 따른 자동 규칙 사용
  • FallLoop → Land: IsInAir == false (땅에 닿은 순간)
  • Land → Idle: Land 애니메이션이 끝났을 때
    • 스테이트의 시퀀스 플레이어에 따른 자동 규칙 사용


2.5. ⚙️ 전체 처리 흐름

[입력 시스템]
  - Axis Mapping: 이동/회전
  - Action Mapping: 점프 등
        ↓
[CharacterMovementComponent]
  - 위치, 속도, 공중 여부(IsFalling) 갱신
        ↓
[AnimBlueprint Event Graph]
  - Get Velocity → Vector Length XY → Speed
  - MovementComponent.IsFalling → IsInAir
        ↓
[AnimGraph StateMachine]
  - 현재 State: Idle / Run / Jump / FallLoop / Land
  - Transition Rule:
      - Idle ↔ Run : Speed 조건
      - Jump → FallLoop : Jump 애니메이션 종료
      - FallLoop → Land : IsInAir == false
      - Land → Idle : Land 애니메이션 종료
        ↓
[각 State 내부 애니메이션 / Blend Space 재생]
        ↓
[Output Pose → 스켈레탈 메시에 적용]

3. 💡 배운 점

  1. 블루프린트만으로도 애니메이션 재생은 가능하지만, 구조적인 한계가 분명하다.
    • Use Animation Asset이나 Play Animation 노드만으로는
      속도와 상태를 고려한 자연스러운 전환을 구현하기 어렵다.
  2. 애니메이션 블루프린트 + 블렌드 스페이스는 “속도 기반 움직임”의 좋은 출발점이다.
    • Speed 한 값으로 Idle ↔ Run이 부드럽게 바뀌는 것만으로도
      게임 느낌이 크게 좋아진다.
  3. 상태(State) 개념이 없으면 점프/낙하/착지 같은 동작은 결국 꼬이기 쉽다.
    • Blend Space는 값(속도)에 강하고,
    • State Machine은 “지금이 어떤 상태인가”를 표현하는 데 강하다.
    • 둘을 조합해서 써야 자연스러운 움직임과 구조적인 이해가 동시에 가능하다.
  4. 구조를 단계적으로 키워가는 게 이해·유지보수 모두에 유리하다.
    • 0단계: 이동만 되는 캡슐
    • 1단계: ABP + Blend Space로 Idle/Run
    • 2단계: State Machine으로 Jump/FallLoop/Land 확장

이 단계를 밟아두면,
이후 공격, 피격, 대시, 상체 에임 등도 같은 패턴으로 자연스럽게 추가할 수 있다.