상태 머신과 애니메이션 Blueprint 연동
이전 절에서 컴포넌트 시스템을 이해하고 활용하는 방법을 배웠습니다. 이제 우리 캐릭터에게 생동감을 불어넣기 위해 애니메이션을 제어하는 방법에 대해 알아보겠습니다. 특히, 복잡한 캐릭터의 동작을 효율적으로 관리하고 애니메이션을 매끄럽게 전환하는 데 필수적인 개념인 상태 머신(State Machine) 과 이를 언리얼 엔진에서 구현하는 애니메이션 블루프린트(Animation Blueprint) 연동에 초점을 맞출 것입니다.
상태 머신(State Machine)이란 무엇인가요?
상태 머신은 어떤 시스템이나 객체가 가질 수 있는 유한한 수의 '상태(State)' 와, 한 상태에서 다른 상태로 전환될 수 있는 '전이(Transition)' 로 구성된 모델입니다. 특정 이벤트가 발생하면 현재 상태에서 정의된 규칙에 따라 다른 상태로 전이됩니다.
게임 캐릭터 애니메이션에서 상태 머신은 매우 강력한 도구입니다. 예를 들어, 캐릭터는 다음과 같은 상태를 가질 수 있습니다.
- Idle (대기): 아무것도 하지 않고 서 있는 상태.
- Walk (걷기): 걷고 있는 상태.
- Run (달리기): 뛰고 있는 상태.
- Jump (점프): 점프 중인 상태.
- Attack (공격): 공격 중인 상태.
각 상태는 고유한 애니메이션을 재생하며, 특정 조건(예: 이동 입력 감지, 점프 버튼 누름, 공격 버튼 누름)이 만족되면 다른 상태로 전이됩니다. 상태 머신을 사용하면 이러한 복잡한 애니메이션 흐름을 명확하고 체계적으로 관리할 수 있습니다.
애니메이션 블루프린트
언리얼 엔진은 상태 머신을 포함한 복잡한 애니메이션 로직을 시각적으로 구현할 수 있도록 애니메이션 블루프린트를 제공합니다. 애니메이션 블루프린트는 특정 스켈레탈 메시 에셋에 연결되어, 해당 스켈레탈 메시를 가진 캐릭터의 애니메이션을 제어합니다.
애니메이션 블루프린트의 주요 부분은 다음과 같습니다.
애님 그래프 (Anim Graph)
- 캐릭터의 스켈레탈 메시의 최종 포즈를 계산하고 적용하는 핵심 그래프입니다.
- 상태 머신(State Machine) 노드가 주로 여기에 위치하여 캐릭터의 주요 동작 상태를 정의하고 관리합니다.
- 여러 애니메이션 클립(Sequence)을 블렌딩하거나, 부분적으로 애니메이션을 적용하는 등의 복잡한 작업을 수행합니다.
이벤트 그래프 (Event Graph)
- 애니메이션 블루프린트가 동작하는 동안 발생하는 이벤트(예:
Event Blueprint Update Animation
)를 처리하고, C++ 코드나 다른 블루프린트로부터 전달받은 변수들을 사용하여 애니메이션 로직을 업데이트합니다. - 여기서 캐릭터의 속도, 점프 상태, 공격 상태 등 게임플레이 관련 변수들을 가져와 애님 그래프의 상태 머신에 전달합니다.
C++와 애니메이션 블루프린트의 연동
C++에서 캐릭터의 이동 속도나 점프 상태와 같은 게임플레이 데이터를 계산한 후, 이 데이터를 애니메이션 블루프린트로 전달하여 올바른 애니메이션이 재생되도록 해야 합니다. 이 과정은 주로 UPROPERTY
매크로를 사용하여 C++ 변수를 블루프린트에 노출하고, 애니메이션 블루프린트의 이벤트 그래프에서 해당 변수를 읽어 애님 그래프의 상태 머신에 전달하는 방식으로 이루어집니다.
애니메이션 관련 변수 선언
ACharacter
를 상속받는 우리의 AMyCharacter
클래스에서 애니메이션에 필요한 변수들을 UPROPERTY
로 선언합니다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
// ... (기존 헤더들) ...
#include "MyCharacter.generated.h"
UCLASS()
class MYFIRSTCPPPROJECT_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
protected:
virtual void BeginPlay() override;
public:
// ... (기존 Tick, SetupPlayerInputComponent 등) ...
protected:
// ... (기존 Input 관련 UPROPERTY 변수들) ...
// 애니메이션 블루프린트에 노출할 변수들
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation")
float CurrentSpeed; // 현재 이동 속도
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation")
bool bIsInAir; // 공중에 떠 있는지 여부
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation")
bool bIsAttacking; // 공격 중인지 여부 (예시)
// 애니메이션 블루프린트에 필요한 데이터를 업데이트하는 함수 (Tick에서 호출)
void UpdateAnimationVariables();
};
애니메이션 관련 변수 업데이트
AMyCharacter.cpp
파일의 Tick
함수 또는 별도의 함수에서 이 변수들의 값을 업데이트합니다.
#include "MyCharacter.h"
// ... (기존 헤더들) ...
#include "GameFramework/CharacterMovementComponent.h" // GetCharacterMovement()를 위해 포함
AMyCharacter::AMyCharacter()
{
// ... (기존 생성자 로직) ...
}
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
// ... (기존 BeginPlay 로직) ...
}
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 매 프레임 애니메이션 관련 변수 업데이트
UpdateAnimationVariables();
}
void AMyCharacter::UpdateAnimationVariables()
{
// 현재 이동 속도 계산 (XY 평면 속도)
CurrentSpeed = GetCharacterMovement()->Velocity.Size2D();
// 공중에 떠 있는지 여부
bIsInAir = GetCharacterMovement()->IsFalling();
// 공격 상태는 추후 공격 시스템 구현 시 설정 (예시)
// bIsAttacking = ...;
}
스켈레탈 메시, 애니메이션 블루프린트 설정
스켈레탈 메시 에셋: 언리얼 엔진 프로젝트에 사용할 캐릭터의 스켈레탈 메시 에셋이 준비되어 있어야 합니다. (예: SK_Mannequin
또는 외부 임포트 모델)
애니메이션 에셋: Idle
, Walk
, Run
, JumpStart
, JumpLoop
, JumpEnd
등의 애니메이션 시퀀스 에셋이 필요합니다.
애니메이션 블루프린트 생성
- 콘텐츠 브라우저에서 사용할 스켈레탈 메시를 찾아 마우스 오른쪽 버튼 클릭 >
Create
>Anim Blueprint
를 선택합니다. - 이름을
ABP_MyCharacter
와 같이 지정합니다.
이벤트 그래프에서 C++ 변수 가져오기
ABP_MyCharacter
를 더블 클릭하여 애니메이션 블루프린트 에디터를 엽니다.
이벤트 그래프(Event Graph)로 이동합니다.
Event Blueprint Update Animation
노드를 찾거나 생성합니다. 이 노드는 매 프레임마다 애니메이션을 업데이트하기 위해 호출됩니다.
이벤트 그래프에 여러분의 C++ 캐릭터 클래스(AMyCharacter
)의 인스턴스를 가져옵니다. Try Get Pawn Owner
노드를 사용하여 현재 애니메이션 블루프린트가 적용된 폰(즉, 우리의 AMyCharacter
인스턴스)을 가져올 수 있습니다.
가져온 폰(AMyCharacter
레퍼런스)에서 드래그하여 Get Current Speed
, Get b Is In Air
, Get b Is Attacking
노드를 추가합니다. (C++에서 UPROPERTY(BlueprintReadOnly)
로 선언했으므로 자동으로 Getter 노드가 생성됩니다.)
이 값들을 애니메이션 블루프린트 내부의 변수에 저장합니다. Set Current Speed
, Set Is In Air
등의 노드를 사용하여 애니메이션 블루프린트의 지역 변수를 업데이트합니다. 이 지역 변수들은 나중에 애님 그래프의 상태 머신에서 사용될 것입니다.
애님 그래프에서 상태 머신 구축
애님 그래프(Anim Graph)로 이동합니다.
'결과 포즈(Result Pose)' 노드 옆에 State Machine (상태 머신)
노드를 추가하고 연결합니다.
상태 머신 노드를 더블 클릭하여 내부로 들어갑니다.
상태 추가
- 'Entry' 노드에서 드래그하여
Idle
상태를 추가합니다. Idle
에서 드래그하여Walk_Run
상태를 추가합니다.Walk_Run
에서 드래그하여Jump
상태를 추가합니다. (또는 별도의 점프 시작/루프/착지 상태를 만들 수도 있습니다)- 필요하다면
Attack
상태 등도 추가합니다.
각 상태에 애니메이션 시퀀스 연결
- 각 상태 노드를 더블 클릭하여 들어갑니다.
Idle
상태에는Idle
애니메이션 시퀀스 에셋을 끌어다 놓고 결과 포즈에 연결합니다.Walk_Run
상태는Blend Space 1D
를 사용하여Walk
와Run
애니메이션을 속도에 따라 블렌딩하도록 설정합니다. (블렌드 스페이스를 미리 생성하고,CurrentSpeed
변수를 X축에 연결합니다.)Jump
상태에는JumpStart
,JumpLoop
(Loop),JumpEnd
애니메이션을 순서대로 연결합니다.
전이 규칙 (Transition Rules) 정의
- 각 상태 사이의 화살표(전이)를 더블 클릭하여 규칙 편집기로 들어갑니다.
Idle
->Walk_Run
전이- 조건:
CurrentSpeed
가 특정 임계값(예: 10.0)보다 크거나 같을 때.
- 조건:
Walk_Run
->Idle
전이- 조건:
CurrentSpeed
가 특정 임계값(예: 10.0)보다 작을 때.
- 조건:
Any State
->Jump
전이 (모든 상태에서 점프 가능)- 조건:
bIsInAir
가True
이고, 특정 애니메이션 시퀀스가 재생 중이 아닐 때. - 점프 착지 시
Jump
->Idle
또는Walk_Run
전이- 조건:
bIsInAir
가False
일 때. - '시간 남음 비율(Time Remaining Ratio)'을 사용하여 점프 착지 애니메이션이 거의 끝났을 때 전이되도록 할 수 있습니다.
- 조건:
- 조건:
이 과정을 통해 여러분은 C++에서 계산된 게임플레이 변수들을 애니메이션 블루프린트로 전달하고, 이 변수들을 사용하여 캐릭터의 복잡한 애니메이션 상태를 제어하는 상태 머신을 구축하게 됩니다.
최종 연동 확인
캐릭터 블루프린트에서 스켈레탈 메시 설정:
여러분의 BP_MyCharacter
블루프린트를 열고, USkeletalMeshComponent
(또는 ACharacter
의 기본 Mesh
컴포넌트)를 선택합니다.
- 'Skeletal Mesh' 항목에 사용할 스켈레탈 메시 에셋을 할당합니다.
- 'Anim Class' 항목에 생성한
ABP_MyCharacter
애니메이션 블루프린트를 할당합니다.
플레이 및 테스트:
언리얼 에디터에서 Play
버튼을 눌러 게임을 실행합니다. 이제 WASD 키로 이동하면 캐릭터가 걷거나 달리는 애니메이션으로 자연스럽게 전환되고, 스페이스바를 누르면 점프 애니메이션이 재생되는 것을 확인할 수 있을 것입니다.
상태 머신과 애니메이션 블루프린트 연동은 언리얼 엔진에서 캐릭터의 생동감 있는 움직임을 구현하는 데 필수적인 기술입니다. C++로 핵심 데이터를 제어하고, 블루프린트로 애니메이션 흐름을 시각적으로 관리하는 이 하이브리드 방식은 개발 효율성을 극대화합니다.