오늘부터는 애니메이션을 캐릭터 클래스에 넣어보자
지금은 매시에 애니메이션 모드를 Use Animation Asset으로 설정해두고 Anim을 Idle로 해둬서 이 애니메이션이 고정된다.
일단 애니메이션/애니메이션 블루프린트를 만들어주자 이때 Skeleton은 캐릭터의 블루프린트의 스켈레톤을 사용해주자
이때 애니메이션 블루프린트에는 Anim Graph이 있다.
Event Graph는 논리적 실행흐름을 다루고 Anim Graph는 캐릭터의 포즈 정보를 다룬다. 사진에 보이는 Result에
포즈 정보를 넘겨주면 캐릭터의 애니메이션이 바뀌게 된다.
이제 매쉬를의 애니메이션 모드를 Use Animation Blueprint로 하고 만든 애니메이션 블루프린트로 지정해주자
그리고 애니메이션 블루프린트에서 Character를 참조할 수 있는 변수를 추가해주자 지금은 null포인터이다.
따라서 이 변수를 초기화해주는 과정이 필요하다
애니메이션 블루프린트의 이벤트 그래프를 보면 두가지가 기본적으로 있는 것을 볼 수 있는데 Try Get Pawn Owner은 이 애니메이션 블루프린트를 사용하는 객체를 가져올 수 있는 것이고 Blueprint Update Animation은 Tick 이벤트와 비슷하게 작동하는 것이다.
이제 Try Get Pawn Owner와 Blueprint Initialize Animation 이벤트를 통해 캐릭터 객체와 그 캐릭터의 움직임에 대한 변수인 Character movement Component를 초기화해주자
그리고 플레이어가 움직이고 있는지를 확인하기 위해 매 프레임마다 Velocity Vector의 x y 요소의 길이를 가지고 와서 초기화 해주자
이 변수를 사용할 수 있도록 Anim Graph에서 State Machine을 만들어주자
State Machine 내부는 Idle과 Run State가 Transition으로 변경될 수 있도록 한다. 이때 Transition은
Ground Speed가 0보다 클 때 Run으로 0일 때 Idle로 가게 만들어준다.
그렇게 해주면 이제 뛰거나 멈춰있는 애니메이션이 재생되는 것을 볼 수 있다.
이제 코드로 구현해보자
일단 Character.cpp 옆에 AnimInstance를 상속받는 클래스를 생성해주자
그리고 헤더파일에서 캐릭터와 무브먼트 변수를 전방선언해주고 속도는 float 변수로 선언해주자
public:
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaTime) override;
UPROPERTY(BlueprintReadOnly)
class ASlashCharacter* SlashCharacter;
UPROPERTY(BlueprintReadOnly, Category = Movement)
class UCharacterMovementComponent* SlashCharacterMovement;
UPROPERTY(BlueprintReadOnly,Category=Movement)
float GroundSpeed;
};
그 다음 캐릭터 포인터변수를 초기화 해줘야한다.
그전에 C++에서의 Cast를 알아보자
static_cast - 컴파일 시간에 실행된다.
dynamic_cast - 런타임에 타입 변환을 수행하고 다형성을 지원
언리얼- Cast 사용
우리는 언리얼의 Cast를 사용할 것이다.
이를 통해 초기화해주고 무브먼트 변수또한 초기화해주자
그리고 GroundSpeed는 KismetMathLibrary 라이브러리의 UKismetMathLibrary::VSizeXY함수를 통해 계산되도록 하자
// Fill out your copyright notice in the Description page of Project Settings.
#include "Characters/SlashAnimInstance.h"
#include "Characters/SlashCharacter.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/KismetMathLibrary.h"
void USlashAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
SlashCharacter = Cast<ASlashCharacter>(TryGetPawnOwner());
if (SlashCharacter)
{
SlashCharacterMovement = SlashCharacter->GetCharacterMovement();
}
}
void USlashAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
Super::NativeUpdateAnimation(DeltaTime);
if (SlashCharacterMovement)
{
GroundSpeed = UKismetMathLibrary::VSizeXY(SlashCharacterMovement->Velocity);
}
}
이렇게 해주면 코드를 통해서 캐릭터의 애니메이션이 변하는 것을 볼 수 있다.
이제 캐릭터가 점프할 수 있도록 만들어보자
점프는 액션매핑을 해준 다음 코드상으로 일단 Character에 내장되어있는 Jump 함수를 사용하도록 하자
SlashCharacter.h
UPROPERTY(EditAnywhere, Category = Input)
UInputAction* JumpAction;
SlashCharacter.cpp
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
여기에 애니메이션을 추가해주자
플레이어가 떨어지고 있는지 확인해줄 변수를 추가하고 매틱마다 그것을 확인할 수 있도록하자
SlashAnimInstance.h
UPROPERTY(BlueprintReadOnly, Category = Movement)
bool IsFalling;
SlashAnimInstance.cpp
void USlashAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
Super::NativeUpdateAnimation(DeltaTime);
if (SlashCharacterMovement)
{
GroundSpeed = UKismetMathLibrary::VSizeXY(SlashCharacterMovement->Velocity);
IsFalling = SlashCharacterMovement->IsFalling();
}
}
그리고 멈춰있는 것과 뛰는 모션을 제외한 주요한 움직임에 관한 애니메이션을 모아두기위해
하나의 State Machine을 추가해주자
그리고 기존에 사용하던 Ground Locomotion을 캐쉬포즈로 저장하여 다른 State Machine에서 사용할 수 있도록 하자
전체흐름도는 아래와 같이 잡고 Transition은 IsFalling을 통해 이루어지도록한다.
여기서 Land -> OnGround 는 Transition을 선택하고 해당 속성을 클릭해준다.
이렇게하면 Jump애니메이션이 작동은 한다. 하지만 원래 OnGround로 돌아오는 것이 너무 느리다.
이때 Land -> OnGround 트랜지션 조건을 추가하고 여기에 Get Relevant Anim Time과 Ground Speed의 bool 연산으로 실행시간이 일정초를 넘고 걷고 있다면 OnGround로 넘어가게 했다.
잘 동작하는 것을 볼 수 있다.
마지막으로 만약 캐릭터가 경사진 곳으로 움직이게 된다면 발이 공중에 뜨게 되는데 이때 Inverse Kinematic을
사용한다.
예를 들어 왼쪽 보다는 오른쪽 캐릭터가 자연스럽다. 이때 캐릭터의 본을 사용하는데 이때 Inverse Kinematic을 통해 계산을 하게된다.
이때 어느 발을 구부려하는 등의 정보는 발에서 디버그 구체를 쏘는 방식으로 결정하게 된다.
이제 실제로 만들어보자
일단 애니메이션/컨트롤릭/컨트롤릭 을 생성해주자
그리고 캐릭터의 뼈를 가져 import해주자 우리가 여기서 사용할 것은 발부분의 가상 뼈나 IK 뼈를 사용할 것이다.
일단 발의 위치에서 일정구간 구로 Trace해서 Trace가 Hit되는 곳의 좌표를 벡터로 반환해주는 함수를 만들어주자
1. 이를 활용하여 왼발 오른발의 Hit 포인트의 Z값을 저장하고 이를 활용해보자
그리고 보간을 통해서 뼈를 이동시킬 것인데 이때 사용할 변수도 추가해주자
2. 보간을 통해 값이 뼈의 이동이 자연스럽게 이루어지도록 하자
3. 골반의 위치는 왼쪽 오른쪽 중에 작은 것의 위치로 지정해주자
4.이 값이 IK 발 쪽 뼈에 적용되도록 하자.
5. IK의 값이 실제 뼈에 적용되도록 하자
이제 애니메이션 블루프린트에서 실제로 사용하면 된다. 이때 Blend 기능과 bool을 통해 떨어지고 있을때와 이동하고
있을 때를 제외했을 때 IK기능이 작동하도록 하면 된다.
이렇게하면 IK가 잘 작동하는 것을 볼 수 있다.
'게임공부 > Unreal Engine' 카테고리의 다른 글
[Unreal Engine][C++]10. The Weapon Class (0) | 2024.07.29 |
---|---|
[Unreal Engine][C++]9. Collision and Overlaps (0) | 2024.07.24 |
[Unreal Engine][C++]7. Character Class (0) | 2024.07.18 |
[Unreal Engine][C++]6.움직이기 (1) | 2024.07.16 |
[Unreal Engine][C++]5.Pawn 클래스 (0) | 2024.07.15 |