본문 바로가기

언리얼C++게임개발/07.애니메이션 시스템의 설계

스테이트 머신 제작

기계가 반복해야 하는 동작을 스테이트로 정의하고 지정된 스테이트의 동작을 반복 수행할 수 있다

캐릭터가 반복해서 재생해야 할 애니메이션 동작을 애니메이션 블루프린트 스테이트 머신이 처리하도록 한다.

  1. 애님 그래프의 빈 공간을 우클릭해 스테이트 머신 새로 추가 클릭 이름을 BaseAction으로 지정
  2. 스테이트 머신을 더블 클릭하고, 머신 편집 윈도우에서 우클릭->스테이트 추가 Ground로 이름 변경
  3. 시작 노드와 추가한 스테이트를 트랜지션으로 연결
    • 트랜지션: 시작->목적 드래그 시 생성되는 단방향 화살표
      • 서로 다른 스테이트끼리 이동이 가능하도록 연결
  4. 추가한 스테이트를 더블 클릭하고 해당 스테이트의 애님 그래프 제작. Blend Poses by bool은 조건에 따라 2가지 애니메이션을 선택해 출력해준다.
  5. 스테이트 작업을 완료하면 컴파일해 애니메이션 시스템 테스트

 

1.4. 점프 기능 구현

ACharacter 클래스의 Jump 멤버 함수를 Jump 입력과 연동시켜 캐릭터의 점프 기능을 구현할 수 있다. Jump 멤버 함수는 입력과 바인딩할 수 있도록 인자와 반환이 없는 함수로 선언되어 있다.

 

ABCharacter.cpp

AABCharacter::AABCharacter()
{
	...
        
	// 캐릭터 무브먼트 컴포넌트를 가져와 JumpZVelocity 값을 변경해 점프 높이 조절
	GetCharacterMovement()->JumpZVelocity = 800.0f;
}

void AABCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
        Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 액션 입력 값과 바인딩
	PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &AABCharacter::Jump);
    
    ...
}
 

 

캐릭터가 점프하는 도중에는 속력이 발생하므로 달리기 애니메이션이 재생된다. 점프 모션을 재생하도록 애니메이션 블루프린트를 수정해보자.

폰의 무브먼트 컴포넌트에서 현재 캐릭터의 이동 상황을 얻어 애니메이션 블루프린트에게 전달할 수 있다.

 

무브먼트 컴포넌트가 제공하는 캐릭터 움직임

  • IsFalling() : 캐릭터가 공중에 떠 있음
  • IsSwimming() : 캐릭터가 수영 중임
  • IsCrouching() :캐릭터가 앉아 있음
  • IsMoveOnGround() : 캐릭터가 땅 위에서 이동

 

ABAnimInstance.h

UCLASS()
class ARENABATTLE_API UABAnimInstance : public UAnimInstance
{
    ...
        
private:
    // 애님 인스턴스에 캐릭터가 공중에 떠 있는지에 대한 불리언 속성 선언
	UPROPERTY(EditAntwhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	bool IsInAir;
    
    ...
};

컴파일하면 블루프린트에 IsInAir 변수가 추가된다. 이변수를 이용해 점프를 위한 애니메이션 시스템을 설계해본다

Ground에서 Jump로 가기 위해서는 IsInAir가 True여야 한다.

 

ABAnimInstance.cpp

UABAnimInstance::UABAnimInstance()
{
	CurrentPawnSpeed = 0.0f;
	IsInAir = false;
}

void UABAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	auto Pawn = TryGetPawnOwner();
	if (::IsValid(Pawn))
	{
		CurrentPawnSpeed = Pawn->GetVelocity().Size();
	}
	auto Character = Cast<ACharacter>(Pawn);
	if (Character)
	{
		// 폰 무브먼트 컴포넌트의 IsFalling 함수를 호출해 두 값을 일치시킴
		IsInAir = Character->GetMovementComponent()->IsFalling();
	}
}

ABCharacter.cpp

AABCharacter::AABCharacter(){
...
GetCharacterMovement()->JumpZVelocity = 800.f;  //점프 속도초기값
}

void AABCharacter::SetupPlayerInputComponent(UInputComponent*PlayerInputComponent){
/...  점프키를 위한 펀션 바인딩
PlayerInputComponent->BindAction(TEXT("Jump"),EInputEvent::IE_Pressed, this, &ACharacter::Jump);
}
 

 

애니메이션 시스템 설계

  1. 스테이트 머신 편집 화면에서 Jump 스테이트 추가
  2. Ground와 Jump 간 양방향 트랜지션 추가
  3. IsInAir을 기반으로 트랜지션 발생 조건 부여
    • 트랜지션의 애니메이션 그래프에서 IsInAir 연결
    • 반전은 Not Boolean 노드 사용

 

결과 화면

 


2. 외부 애니메이션 적용

2.1. 애니메이션 리타겟

인간형 캐릭터에서 다른 마네킹의 애니메이션을 사용하고 싶을 경우 애니메이션 리타겟 기능을 활용해보자. 스켈레톤의 구성이 달라도 애니메이션 리타겟 기능을 사용하면 애니메이션을 재생할 수 있다.

 

애니메이션 리타겟 사용 과정

  1. 애니메이션을 교환할 캐릭터들의 스켈레톤 세팅
    • 마네킹의 스켈레톤 메시 에디터 오픈
    • 툴바 리타겟 매니저 -> 릭 셋업 -> 릭 선택 -> 인간형 릭
    • 리타겟 설정이 완료된 마네킹 스켈레탈 애셋 저장
    • 캐릭터의 스켈레탈도 같은 인간형 릭에 매핑
  2. 마네킹의 점프 애셋을 선택하고 우클릭 -> 애님 애셋 리타겟 -> 애님 애셋 복제 후 리타겟
  3. 애니메이션을 옮길 대상 스켈레톤 지정
  4. 대체 메뉴에 변환할 정보 기입
  5. 복제될 애니메이션 애셋이 저장될 대상 폴더 지정
  6. 좌측 하단의 리타겟 버튼을 눌러 애니메이션 리타겟
  7. 새로 생성된 애니메이션 애셋 모두 저장

 

릭 매핑 이후 애니메이션 에셋 리타겟 과정

 

2.2. 점프 구현

점프 동작(도약-체공-착지)에 따라 애니메이션 종류와 재생 시간을 다르게 해 자연스러운 점프 기능을 구현해보자.

도약과 착지 상황에서는 애니메이션을 한 번만 재생하고 체공 상황에서는 몸이 부양하는 애니메이션을 반복 재생한다.

 

애니메이션 조절

  1. 스테이트 확장(Ground->JumpStart, JumpLoop->JumpEnd)
  2. 스테이트별 트랜지션 조건을 다르게 지정
  3. 각 스테이트마다 애니메이션 배치 후 최종 포즈와 연결
    • 한 번만 재생할 경우 Loop Animation 옵션 해제
  4. JumpStart->JumpLoop 트랜지션 생성
    • 스테이트에 애니메이션을 설정하면 트랜지션에서 해당 스테이트 애니메이션 관련 노드 사용 가능
  5. Time Remaining 노드 생성
    • 스테이션에서 사용한 애니메이션 재생의 남은 시간 반환
      • ratio 속성 노드 선택 시 애니메이션 재생 시간비 반환(eg. 0.1 -> 10%)
  6. 남은 시간 비율이 0.1보다 작으면 스테이트를 이동하도록 노드 연결
  7. 단발성 애니메이션 트랜지션의 Automatic Rule Based on Sequence Player in State 체크
    • 애니메이션 종료 시 자동으로 스테이트 전환

 

트랜지션 시간비 설정

스테이트 트랜지션이 가능한지 평가해야 하므로 bool형식으로 변환해야 한다.

 

결과 화면