[이득우의 언리얼 C++ 게임 개발의 정석] Chapter 7. 애니메이션 시스템의 설계

수민·2023년 3월 17일
0
post-thumbnail

이득우의 언리얼 C++ 게임 개발의 정석을 읽고 개인 공부 목적으로 요약 정리한 글입니다!


👀 애니메이션 블루프린트

애니메이션 블루프린트

: 다양한 상황에 적절한 애니메이션을 체계적으로 재생하도록 하는 애니메이션 시스템 제작 도구
애님그래프와 애님 인스턴스로 구성된다.

애님 인스턴스 (Anim Instance)

블루프린트의 기반을 이룬다.
Skeletal Mesh를 소유하는 Pawn의 정보를 받아 애님 그래프가 참조할 데이터를 제공
C++ / Blueprint 모두 가능

애님 그래프 (Anim Graph)

시각적 도구를 이용하여 애니메이션 시스템을 제작할 수 있다
애님 인스턴스의 변수 값에 따라 변화하는 애니메이션 시스템을 설계하는 공간
Blueprint에서만 제작 가능


👀 폰과 데이터 연동하여 애니메이션 재생

class HUNT_PROTOTYPE_API UMyAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
	
private:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true));
	float CurrentPawnSpeed;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = ture));
	bool IsInAir;

public:
	UMyAnimInstance();

	virtual void NativeUpdateAnimation(float DeltaTime) override;
};


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

void UMyAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
	Super::NativeUpdateAnimation(DeltaTime);

	APawn* Pawn = TryGetPawnOwner();
	if (::IsValid(Pawn)) {
		CurrentPawnSpeed = Pawn->GetVelocity().Size();

		auto Character = Cast<ACharacter>(Pawn);
		if (Character) {
			IsInAir = Character->GetMovementComponent()->IsFalling();
		}
	}
}

IDLE / 달리기 / 점프 구현을 위해
CurrentPawnSpeed, IsInAir 변수를 선언하고
AnimInstance에서 Pawn의 정보를 받아와서 변수와 연동해준다.

🔥 Pawn에서 AnimInstance에 접근하면 안될까?
해도 괜찮긴 함. 멀쩡하게 동작함
But 애니메이션이 필요없는 서버 코드에서 문제가 발생할 수 있다
(애니메이션 로직과 폰의 로직의 분리가 어려움)
따라서 AnimInstance에서 Pawn을 접근하자.

Tick마다 호출되는 NativeUpdateAnimation() 함수 통해 연동해준다.
(AnimInstance 클래스에서 제공하는 가상함수)

TryGetPawnOwner() 함수를 통해 현재 폰을 받아오고, 정보를 연동한다.

🔥 언리얼 Tick 내부 로직 순서
사용자 입력 받아오기 -> 폰 움직이기 -> 애니메이션 재생
따라서 폰이 사라지면 애니메이션을 재생하면 안됨.
그래서 Pawn이 유효한지 항상 검사해줘야 한다


👀 스테이트 머신

스테이트 머신 (State Machine)

유한 상태 기계 방식.

스테이트(State) : 캐릭터가 반복해서 재생해야 할 애니메이션 동작
트랜지션 (Transition) : 각 State 사이를 이동하기 위한 조건

하나의 State만 지정해서 해당 State에서 지정한 동작을 수행하도록 한다.


👀 점프 구현

점프중인지 알아보자

점프할 때 점프 애니메이션을 띄우려면 플레이어가 점프중인지 알 수 있어야 한다.
어케아냐고?

Pawn의 MovementComponent가 함수들을 제공해준다.
물론,, 이걸 쓸 수 있는 컴포넌트는 Character Movement 컴포넌트 뿐이다 (당연함)

  • IsFalling() : 현재 공중에 떠있는가?
  • IsSwimming() : 현재 수영중인가?
  • IsCrouching() : 현재 쭈그리고 앉아있는가?
  • IsMoveOnGround() : 현재 땅에서 이동중인가?

여기서 IsFalling() 함수를 통해 현재 Pawn이 점프중인지 정보를 받아와서 AnimInstance에 저장
그리고 그 값을 통해 애님 그래프에서 애니메이션을 재생한다.

구현

위 사진이 점프를 구현한 상태의 스테이트 머신이다.

저기서 트랜지션을 보면,

이게 Ground -> JumpLoop.
현재 점프중이면 JumpLoop를 재생하고
JumpLoop에는

요렇게 점프 애니메이션을 넣는다.

마찬가지로
점프가 끝나면? (트랜지션 상 IsInAir == false)
JumpEnd에 착지하는 애니메이션을 넣어준다.

근데 얘네들은 계속 루프돌면서 재생되면 안되고, 한 번만 재생되어야 하므로

여기서 현재 체크되어 있는 애니메이션 루프 를 선택 해제 해준다.

그리구,

점프를 착지했으면 다시 Ground 애니메이션으로 돌아와야 한다.
조건 : 착지 애니메이션 재생이 끝났을 때.

이걸 쉽게 해줄 수 있는 옵션이 있다

스테이트의 시퀀스 플레이어에 따른 자동 규칙
(Automatic Rule Based on Sequence Player in State)
옵션을 체크하면,
애니메이션 종료 시 자동으로 스테이트가 전환된다.


끝!
괜찮쥬?

😊 느낀점
사실 애니메이션,, 진짜 어려운 느낌이었다
전에 혼자 유튜브보면서 해볼때,, 엄청 애먹었다 특히 점프할 때
근데 확실히 책을 보면서 따라가니까 이해가 잘 됐다!

profile
우하하

0개의 댓글