[UE] Character Animation, Collsion
언리얼 엔진 C++에서 캐릭터 애니메이션은 게임이나 다른 대화형 경험에서 캐릭터의 동작과 움직임을 제어하기 위해 코
드를 작성하는 것이다. 이는 언리얼 엔진의 여러 C++ 클래스 및 함수, 예를 들어 캐릭터 클래스와 애니메이션 블루프린트 시스템을 사용하여 달성할 수 있다.
목차
Character Animation
애니메이션을 가지고 있으면, C++ 코드를 사용하여 애니메이션의 타이밍 및 블렌딩을 제어하고, 플레이어 및 다른 게임 시스템에서의 입력 처리와 같은 작업을 수행할 수 있다. 이는 PlayAnimMontage()와 같은 함수를 사용하여 특정 애니메이션 시퀀스를 재생하고, 애니메이션 상태 기계를 설정하여 애니메이션이 서로 전환하는 방식을 제어하는 것을 포함할 수 있다.
언리얼 엔진 C++에서의 캐릭터 애니메이션은 3D 모델링 및 애니메이션 소프트웨어, 언리얼 엔진의 애니메이션 블루프린트 시스템 및 C++ 프로그래밍의 조합을 사용하여 게임이나 다른 대화형 경험에서 캐릭터의 동작과 움직임을 제어하는 것을 의미한다.
01_Spawn | |
C01_Properties.h .cpp C02_Mesh C02_Mesh_Sphere C02_Mesh_Cone C03_Spawner.h .cpp |
|
02_Profiler | |
C01_Log.h .cpp C02_DrawDebug.h .cpp |
|
03_Collision | |
C01_ActorOverlap.h .cpp 생성 | |
Utilities | |
CHelpers.h | |
CAnimInstance.h .cpp CGameMode.h .cpp CPlayer |
CHelper - 체크용 매크로 추가
CHelper.h
#pragma once
#include "CoreMinimal.h"
//검증용 매크로
#define CheckTrue(x) { if(x == true) return; }
#define CheckTrueResult(x, y) { if(x == true) return y; }//리턴이 필요한 경우
#define CheckFalse(x) { if(x == false) return;}
#define CheckFalseResult(x, y) { if(x == false) return y;}//리턴이 필요한 경우
#define CheckNull(x) { if(x == nullptr) return;} //nullptr일 때 리턴
#define CheckNullResult(x, y) { if(x == nullptr) return y;}//리턴이 필요한 경우
#define CreateTextRender()\
{\
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);\
Text->SetRelativeLocation(FVector(0, 0, 100));\
Text->SetRelativeRotation(FRotator(0, 180, 0));\
Text->SetRelativeScale3D(FVector(2));\
Text->TextRenderColor = FColor::Red;\
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;\
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));\
}
//아래부분 변경사항 없음
class U2212_03_API CHelpers
{
public:
template<typename T>
static void CreateComponent(AActor* InActor, T** OutComponent, FName InName, USceneComponent* InParent = nullptr)
{
*OutComponent = InActor->CreateDefaultSubobject<T>(InName);
if (!!InParent)
{
(*OutComponent)->SetupAttachment(InParent);
return;
}
InActor->SetRootComponent(*OutComponent);
}
template<typename T>
static void GetAsset(T** OutObject, FString InPath)
{
ConstructorHelpers::FObjectFinder<T> asset(*InPath);
*OutObject = asset.Object;
}
template<typename T>
static void GetAssetDynamic(T** OutObject, FString InPath)
{
*OutObject = Cast<T>(StaticLoadObject(T::StaticClass(), nullptr, *InPath));
}
template<typename T>
static void GetClass(TSubclassOf<T>* OutClass, FString InPath)
{
ConstructorHelpers::FClassFinder<APawn> asset(*InPath);
*OutClass = asset.Class;
}
};
검증용 매크로 추가
- #define CheckTrue(x) { if(x == true) return; }
- #define CheckTrueResult(x, y) { if(x == true) return y; }
- #define CheckFalse(x) { if(x == false) return;}
- #define CheckFalseResult(x, y) { if(x == false) return y;}
- #define CheckNull(x) { if(x == nullptr) return;}
- #define CheckNullResult(x, y) { if(x == nullptr) return y;}
TextRender 매크로 추가
- #define CreateTextRender()
- TextRender는 자주 사용하므로 매크로로 사용하도록 추가하였다.
- FRotator(0, 180, 0)는 Pitch, Yaw, Roll 순서이다. C++에서의 rotator 순서.
- Text->Text = FText::FromString(GetName().Replace(L"Default__", L""))
- 위의 코드는 TextRender 앞부분에 Default__ 부분을 없애기위해 사용.
CAnimInstance
CAnimInstance.h
#pragma once
#include "CoreMinimal.h" //Actor를 가지고 있다. But, Pawn과 Character는 없다.
#include "Animation/AnimInstance.h"
#include "CAnimInstance.generated.h"
UCLASS()
class U2212_03_API UCAnimInstance : public UAnimInstance
{
GENERATED_BODY()
protected:
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation")
float Speed;
public:
//언리얼에서 오버라이딩 했으면 override 붙여준다. 의무사항
void NativeBeginPlay() override;
void NativeUpdateAnimation(float DeltaSeconds) override;
private:
class ACharacter* OwnerCharacter;
};
- #include "CoreMinimal.h"
- CoreMinimal 헤더는 Actor를 가지고 있다. 하지만 Pawn과 Character는 없다.
- 따라서 캐릭터를 사용하기 위해 CAnimInstance.cpp에 "GameFramework/Character.h"를 추가한다.
CAnimInstance.cpp
#include "CAnimInstance.h"
#include "Global.h"
#include "GameFramework/Character.h"
void UCAnimInstance::NativeBeginPlay()
{
Super::NativeBeginPlay();
OwnerCharacter = Cast<ACharacter>(TryGetPawnOwner());
}
void UCAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
CheckNull(OwnerCharacter); //nullptr일 때 실행X. nullptr체크. CHelper에서 만든 검증 매크로 사용.
Speed = OwnerCharacter->GetVelocity().Size2D();//Velocity의 크기를 사용.
}
Runtime Mode가 아닌 경우에도 블루프린트 업데이트 애니메이션은 테스트용 Pawn들 때문에 블루프린트 에디터(Blueprint Editor) 상에서도 실행된다.
- 그래서 우리가 체크하기 위해 TryGetPawnOwner 캐릭터용으로 캐스팅한다.
- OwnerCharacter = Cast<ACharacter>(TryGetPawnOwner());
Velocity의 크기
※ 부모를 콜하는 방법 - 일반적인 방법, 언리얼 Super 키워드
void UCAnimInstance::NativeBeginPlay()
{
UAnimInstance::NativeBeginPlay(); //일반적인 방법
Super::NativeBeginPlay(); //언리얼에서 지원하는 Super키워드 사용
}
void UCAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
UCAnimInstance::NativeUpdateAnimation(DeltaSeconds);
Super::NativeUpdateAnimation(DeltaSeconds);
}
ABP_Character 생성
애니메이션 - 애니메이션 블루프린트 - CAnimInstance, Skel_Mannequin - ABP_Character 생성
AnimGraph
Actor이외에 Editor에 값을 노출시켜야 한다면 EditAnywhere로 설정하여야 한다.
CPlayer
CPlayer.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "CPlayer.generated.h"
UCLASS()
class U2212_03_API ACPlayer : public ACharacter
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USpringArmComponent* SpringArm;
UPROPERTY(VisibleAnywhere)
class UCameraComponent* Camera;
public:
ACPlayer();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
void OnMoveForward(float InAxisValue);
void OnMoveRight(float InAxisValue);
void OnHorizontalLook(float InAxisValue);
void OnVerticalLook(float InAxisValue);
private:
void OnRun();
void OffRun();
};
CPlayer.cpp
#include "CPlayer.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
// Sets default values
ACPlayer::ACPlayer()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetCapsuleComponent());
CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
USkeletalMesh* mesh;
//SK_Mannequin을 레퍼런스 복사하여 경로를 넣어준다.
CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
GetMesh()->SetSkeletalMesh(mesh);
GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
TSubclassOf<UCAnimInstance> animInstance;
CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
GetMesh()->SetAnimClass(animInstance); //Mesh에 animInstance 할당
bUseControllerRotationYaw = false;
GetCharacterMovement()->bOrientRotationToMovement = true; //이동방향으로 회전
GetCharacterMovement()->MaxWalkSpeed = 400;
SpringArm->SetRelativeLocation(FVector(0, 0, 60));
SpringArm->TargetArmLength = 200;
SpringArm->bUsePawnControlRotation = true;
SpringArm->bEnableCameraLag = true;
}
// Called when the game starts or when spawned
void ACPlayer::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ACPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) //입력
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", this, &ACPlayer::OnMoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ACPlayer::OnMoveRight);
PlayerInputComponent->BindAxis("HorizontalLook", this, &ACPlayer::OnHorizontalLook);
PlayerInputComponent->BindAxis("VerticalLook", this, &ACPlayer::OnVerticalLook);
PlayerInputComponent->BindAction("Run", EInputEvent::IE_Pressed, this, &ACPlayer::OnRun);
PlayerInputComponent->BindAction("Run", EInputEvent::IE_Released, this, &ACPlayer::OffRun);
}
void ACPlayer::OnMoveForward(float InAxisValue)
{
FRotator rotator = FRotator(0, GetControlRotation().Yaw, 0);
FVector direction = FQuat(rotator).GetForwardVector();
AddMovementInput(direction, InAxisValue); //이동
}
void ACPlayer::OnMoveRight(float InAxisValue)
{
FRotator rotator = FRotator(0, GetControlRotation().Yaw, 0);
FVector direction = FQuat(rotator).GetRightVector();
AddMovementInput(direction, InAxisValue); //이동
}
void ACPlayer::OnHorizontalLook(float InAxisValue)
{
AddControllerYawInput(InAxisValue);
}
void ACPlayer::OnVerticalLook(float InAxisValue)
{
AddControllerPitchInput(InAxisValue);
}
void ACPlayer::OnRun()
{
GetCharacterMovement()->MaxWalkSpeed = 600;
}
void ACPlayer::OffRun()
{
GetCharacterMovement()->MaxWalkSpeed = 400;
}
AnimInstance를 사용하기 위해 헤더를 추가한다.
- #include "CAnimInstance.h"
Mesh에 animInstance를 할당한다.
- TSubclassOf<UCAnimInstance> animInstance;
- CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
- GetMesh()->SetAnimClass(animInstance);
BindAction
- PlayerInputComponent->BindAction("Run", EInputEvent::IE_Pressed, this, &ACPlayer::OnRun);
- 눌렀을 때 this에 ACPlayer에 있는 OnRun을 연결시켜준다.
- IE_Axis: 축 값 입력
- IE_DoubleClick: 더블 클릭
- IE_Pressed: 눌렀느냐
- IE_Released: 누르고 떼었느냐
- IE_Repeat: 누르고 있느냐
C01_ActorOverlap
새 C++ 클래스 - Actor - C01_ActorOverlap 생성
C01_ActorOverlap.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C01_ActorOverlap.generated.h"
UCLASS()
class U2212_03_API AC01_ActorOverlap : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UBoxComponent* Box;
UPROPERTY(VisibleAnywhere)
class UTextRenderComponent* Text;
public:
AC01_ActorOverlap();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void BeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
UFUNCTION()
void EndOverlap(AActor* OverlappedActor, AActor* OtherActor);
};
C01_ActorOverlap.cpp
#include "03_Collision/C01_ActorOverlap.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC01_ActorOverlap::AC01_ActorOverlap()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->bHiddenInGame = false; //Unreal C++에서는 bool형에 앞에 b를 붙여준다.
Box->SetRelativeScale3D(FVector(3));
}
void AC01_ActorOverlap::BeginPlay()
{
Super::BeginPlay();
OnActorBeginOverlap.AddDynamic(this, &AC01_ActorOverlap::BeginOverlap);
OnActorEndOverlap.AddDynamic(this, &AC01_ActorOverlap::EndOverlap);
}
void AC01_ActorOverlap::BeginOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
FString str = FString::Printf(L"Begin - Overlapped : %s, Other : %s", *OverlappedActor->GetName(), *OtherActor->GetName());
CLog::Print(str);
}
void AC01_ActorOverlap::EndOverlap(AActor * OverlappedActor, AActor * OtherActor)
{
FString str = FString::Printf(L"End - Overlapped : %s, Other : %s", *OverlappedActor->GetName(), *OtherActor->GetName());
CLog::Print(str, -1, 10, FColor::Red);
}
TextRender "Default__" 지우기
- CHelpers 매크로 활용.
※ Runtime에 사용될 Delegation에 연결된 함수들은 전부 직렬화되어야 한다.
우클릭 - 새 C01_ActorOverlap 기반 블루프린트 클래스 생성 - BP_C01_ActorOverlap 생성
DELEGATE
DECLARE_DELEGATE
1:1 매핑. 블루프린트에서 공개X. Return 존재O
DECLARE_MULTICAST
1:n 매핑. 블루프린트에서 공개X. Return 존재X
EVENT
DYNAMIC
1:1 매핑. 블루프린트에서 공개O. Return 존재O
DYNAMIC MULTICAST
1:n 매핑. 블루프린트에서 공개O. Return 존재X
DYNAMIC_SPARSE_MULTICAST
-1:n 매핑. 블루프린트에서 공개O. Return 존재X ??
- DELEGATE 타입, 클래스, 명, ___, ___, ___, ____
가장 엄격한 방법. 충돌에 많이 사용.
타입, 변수명 일치시켜야 한다.
https://darkcatgame.tistory.com/66
실행화면
'⭐ Unreal Engine > UE FPS TPS' 카테고리의 다른 글
[UE] Collsion(trigger, MultiTrigger, Explosion) (0) | 2023.03.13 |
---|---|
[UE] Collision(Overlap, hit) (0) | 2023.03.09 |
[UE] Character, GameMode (0) | 2023.03.07 |
[UE] Log 출력하기, Draw Debug 구현 (0) | 2023.03.03 |
[UE] Mesh, Log (0) | 2023.03.02 |
댓글
이 글 공유하기
다른 글
-
[UE] Collsion(trigger, MultiTrigger, Explosion)
[UE] Collsion(trigger, MultiTrigger, Explosion)
2023.03.13 -
[UE] Collision(Overlap, hit)
[UE] Collision(Overlap, hit)
2023.03.09 -
[UE] Character, GameMode
[UE] Character, GameMode
2023.03.07 -
[UE] Log 출력하기, Draw Debug 구현
[UE] Log 출력하기, Draw Debug 구현
2023.03.03