[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 타입, 클래스, 명, ___, ___, ___, ____
가장 엄격한 방법. 충돌에 많이 사용.
타입, 변수명 일치시켜야 한다.
델리게이트
C++ 오브젝트 상의 멤버 함수를 가리키고 실행시키는 데이터 유형입니다.
docs.unrealengine.com
https://darkcatgame.tistory.com/66
UE4 C++ Delegate 정리 & 샘플 프로젝트
개인적으로 UE4 C++에서 Delegate를 사용할 때 처음에 굉장히 에러를 많이 겪었습니다, 그래서 이번 포스팅은 UE4 C++에서 Delegate를 사용하는 방법에 대해 정리하고 샘플프로젝트도 만들었습니다. https
darkcatgame.tistory.com
실행화면

'⭐ 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
댓글을 사용할 수 없습니다.