[ 애니메이션 ]
- 애니메이션 몽타주 -
(언리얼 에디터) 콘텐츠 브라우저 -> Player -> 우클릭_애니메이션-애니메이션 몽타주 : "MTGWukongAttack"
// 보라색 에셋 : 몽타주
// 일반 시퀀스들과 다루는 방식이 다름.
(언리얼 에디터-MTGWukongAttack) 몽타주-DefalutGroup DefalutSlot-슬롯매니저
(언리얼 에디터-MTGWukongAttack) 애님 슬롯 매니저-그룹 추가 : "Skill"
(언리얼 에디터-MTGWukongAttack) 애님 슬롯 매니저-슬롯 추가 : "Skill1"
(언리얼 에디터-MTGWukongAttack) 몽타주-DefalutGroup DefalutSlot-슬롯이름 : "Skill.Skill1
(언리얼 에디터-MTGWukongAttack) 에셋 브라우저 : "Primary_Melee_A_Slow" DefalutGroup DefaultSlot에 드래그
(언리얼 에디터-MTGWukongAttack) Primary_Melee_A_Slow -> 디테일-애니메이션 세그먼트-재생속도 : "2.0"
(언리얼 에디터-MTGWukongAttack) 에셋 브라우저 : "Primary_Melee_B_Slow" DefalutGroup DefaultSlot에 드래그
(언리얼 에디터-MTGWukongAttack) Primary_Melee_B_Slow-> 디테일-애니메이션 세그먼트-재생속도 : "2.0"
// 연속 모션을 만들 수 있음.
(언리얼 에디터-BPWukongAnim) AnimGraph -> 우클릭_"Defult Slot"
(언리얼 에디터-BPWukongAnim) Defult Slot -> 디테일-세팅-Slot Name : "Skil.Skill1"
// Ground->Skill1->최종 애니메이션 포즈로 연결된 경우,
// 특정 몽타주 포즈를 작동시키라고 명령을 하지 않으면 원본 포즈가 작동됨.
// 특정 몽타주 포즈를 작동시키라고 명령을 하면 원본 포즈는 무시하고 몽타주 포즈가 동작이 됨.
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-입력 -> 액션 매핑 : "QuickSlot1" "1"
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-입력 -> 액션 매핑 : "QuickSlot2" "2"
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-입력 -> 액션 매핑 : "QuickSlot3" "3"
(C++-WukongAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PlayerBaseAnim.h"
#include "WukongAnim.generated.h"
UENUM(BlueprintType, Meta = (Bitflags)) // enum문을 사용할 때 사용.
enum class EWukongAnim : uint8 // uint8로 사용하겠다고 설정.
{
Idle,
Run,
Attack,
Hit,
Jump
};
UCLASS()
class PROJECT1005_API UWukongAnim : public UPlayerBaseAnim
{
GENERATED_BODY()
public:
UWukongAnim();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EWukongAnim"))
uint8 AnimType;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EWukongAnim"))
UAnimMontage* Skill1Montage;
public:
// UAnimInstance에 가상함수로 정의되어 있으므로 재정의 하여 사용할 수 있음.
virtual void NativeInitializeAnimation(); // 초기화될 때 사용.
virtual void NativeUpdateAnimation(float DeltaSeconds); // 매 프레임마다 생성.
public:
virtual void InheritMoveStopNotify();
virtual void InheritAttackEndNotify();
virtual void InheritInIdleNotify();
virtual void InheritNormalAttack();
public:
void Skill1();
};
(C++-WukongAnim.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "WukongAnim.h"
#include "PlayerWukong.h"
UWukongAnim::UWukongAnim() // 생성자.
{
BaseAnimType = &AnimType;
NextAttackEnable = true; // Wukong에서는 가능.
NextAttackMax = 5;
// 몽타주 에셋 읽음,
static ConstructorHelpers::FObjectFinder<UAnimMontage> Skill1Asset(TEXT("AnimMontage'/Game/Player/MTGWukongAttack.MTGWukongAttack'"));
if (Skill1Asset.Succeeded())
Skill1Montage = Skill1Asset.Object;
}
void UWukongAnim::NativeInitializeAnimation() // 초기화될 때 사용.
{
Super::NativeInitializeAnimation();
}
void UWukongAnim::NativeUpdateAnimation(float DeltaSeconds) // 매 프레임마다 생성.
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 언리얼에서는 Cast를 사용하여 형변환을 해야 함.
APlayerWukong* pOwner = Cast<APlayerWukong>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner)) // IsValid : U오프젝트에 대한 유효성 검사를 해줌. 제대로 된 것인지 확인을 해줘서 더 안전함.
{
UCharacterMovementComponent* pMovement = pOwner->GetCharacterMovement(); // Movement를 얻어옴.
if (IsValid(pMovement))
{
}
}
}
void UWukongAnim::InheritMoveStopNotify()
{
}
void UWukongAnim::InheritAttackEndNotify()
{
}
void UWukongAnim::InheritInIdleNotify()
{
}
void UWukongAnim::InheritNormalAttack()
{
}
void UWukongAnim::Skill1()
{
if (!Montage_IsPlaying(Skill1Montage))
Montage_Play(Skill1Montage);
}
(C++-PlayerWukong.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PlayerCharacter.h"
#include "PlayerWukong.generated.h"
/**
*
*/
UCLASS()
class PROJECT1005_API APlayerWukong : public APlayerCharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerWukong();
protected:
// UPROPERTY : 사용하지 않으면 언리얼 에디터에 공개가 되지 않음. 내부적인 변수로 사용할 수 있음.
// 언리얼 에디터에 연결하여 사용하려면 변수를 선언하기 전에 프로퍼티로 변수의 속성을 지정해줘야 함.
// Category : Camera로 설정.
// VisibleAnywhere : 다 보이지만 편집을 할 수 없음.
// EditAnywhere : 에디터에서도 편집 가능.
UPROPERTY(Category = Camera, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
UCameraComponent* Camera;
UPROPERTY(Category = Camera, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
USpringArmComponent* Arm;
class UWukongAnim* WukongAnim; // 포인터 변수 선언.
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
void MoveFront(float fScale); // 앞뒤로 이동.
void MoveSide(float fScale); // 좌우로 이동.
void RotationZ(float fScale); // 회전.
void JumpKey(); // 점프.
void NormalAttack(); // 공격.
void QuickSlot1();
void QuickSlot2();
void QuickSlot3();
};
(C++-PlayerWukong.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerWukong.h"
#include "WukongAnim.h"
// Sets default values
APlayerWukong::APlayerWukong()
{
// 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;
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); // 카메라 컴포넌트 생성. 생성자에서 생성해야 함.
Arm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Arm")); // Sprint Arm 컴포넌트 생성.
// 셀카봉 같은 느낌.
Arm->SetupAttachment(GetMesh()); // Arm의 부로모 Mesh를 지정.
Camera->SetupAttachment(Arm); // 카메라의 부모로 Arm을 지정.
// 애니메이션 클래스 지정.
static ConstructorHelpers::FClassFinder<UWukongAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Player/BPWukongAnim.BPWukongAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
// 점프의 속도 조절.
// GetCharacterMovement()->JumpZVelocity // JumpZVelocity : 위로 올라가는 속도.
}
// Called when the game starts or when spawned
void APlayerWukong::BeginPlay()
{
Super::BeginPlay(); // 이 액터가 레벨에 입장할 때 배치되고 게임이 시작할 때 딱 한 번만 호출됨.
WukongAnim = Cast<UWukongAnim>(GetMesh()->GetAnimInstance()); // WraithAnim을 받아옴.
}
// Called every frame
void APlayerWukong::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); // 게임이 동작되는 매프레임마다 호출되는 함수.
}
// Called to bind functionality to input
// UInputComponent : 입력받은 것을 연결해서 호출해줄 함수를 연결하는 바인딩 역할을 함.
void APlayerWukong::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent); // 플레이어 컨트롤러가 빙의가 된 후에 호출.
// 언리얼은 유니코드 문자열을 사용하기 때문에 TEXT("")를 사용해야 함.
// this : 어떤 객체를 쓸 것인지.
PlayerInputComponent->BindAxis(TEXT("MoveFront"), this, &APlayerWukong::MoveFront);
PlayerInputComponent->BindAxis(TEXT("MoveSide"), this, &APlayerWukong::MoveSide);
PlayerInputComponent->BindAxis(TEXT("RotationZ"), this, &APlayerWukong::RotationZ);
// EInputEvent::IE_Pressed : 눌렀을 때.
// EInputEvent::IE_Released : 눌렀다가 뗐을 때.
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &APlayerWukong::JumpKey);
PlayerInputComponent->BindAction(TEXT("NormalAttack"), EInputEvent::IE_Pressed, this, &APlayerWukong::NormalAttack);
PlayerInputComponent->BindAction(TEXT("QuickSlot1"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot1);
PlayerInputComponent->BindAction(TEXT("QuickSlot2"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot2);
PlayerInputComponent->BindAction(TEXT("QuickSlot3"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot3);
}
void APlayerWukong::MoveFront(float fScale) // 앞뒤로 이동.
{
// GetActorForwardVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 앞으로, -1이면 뒤로 가게 됨.
AddMovementInput(GetActorForwardVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 앞으로.
WukongAnim->SetMoveDir(EDir::Front);
else if (fScale < 0.f) // 뒤로.
WukongAnim->SetMoveDir(EDir::Back);
}
}
void APlayerWukong::MoveSide(float fScale) // 좌우로 이동.
{
// GetActorRightVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 오른쪽으로, -1이면 왼쪽으로 가게 됨.
AddMovementInput(GetActorRightVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 오른쪽으로.
WukongAnim->SetMoveDir(EDir::Right);
else if (fScale < 0.f) // 왼쪽으로.
WukongAnim->SetMoveDir(EDir::Left);
}
}
void APlayerWukong::RotationZ(float fScale) // 회전.
{
AddControllerYawInput(fScale);
}
void APlayerWukong::JumpKey() // 점프.
{
Jump(); // Jump를 지원해줌.
}
void APlayerWukong::NormalAttack() // 공격.
{
if (IsValid(WukongAnim))
WukongAnim->NormalAttack();
}
void APlayerWukong::QuickSlot1()
{
if (IsValid(WukongAnim))
WukongAnim->Skill1();
}
void APlayerWukong::QuickSlot2()
{
}
void APlayerWukong::QuickSlot3()
{
}
// 몽타주를 실행하게 되면 몽타주 포즈를 실행하고 다시 처음 모션을 시작하게 됨.
// 모션 처리를 해줘야 함.
- Jump -
(언리얼 에디터-BPWukongAnim) AnimGraph -> Ground
(언리얼 에디터-BPWukongAnim) Ground_드래그 : "Jump" -> 디테일-Events-Always Reset on Entry : "체크"
// 다른 동작과 Jump 연결.
(언리얼 에디터-BPWukongAnim) Idle->Jump 연결
(언리얼 에디터-BPWukongAnim) Jum ->Idle 연결
(언리얼 에디터-BPWukongAnim) Jum ->Idle-트랜지션 룰
(언리얼 에디터-BPWukongAnim) 우클릭_"Get Anim Type" -> Equal(Enum) : "Idle"
(언리얼 에디터-BPWukongAnim) Equal(Enum) : Idle와 결과 연결
(언리얼 에디터-BPWukongAnim) Idle->Jump-트랜지션 룰
(언리얼 에디터-BPWukongAnim) 우클릭_"Get Anim Type" -> Equal(Enum) : "Jump"
(언리얼 에디터-BPWukongAnim) Equal(Enum) : Jump와 결과 연결
(언리얼 에디터-BPWukongAnim) Ground->Jump-트랜지션 룰
(언리얼 에디터-BPWukongAnim) 우클릭_"Get Anim Type" -> Equal(Enum) : "Jump"
(언리얼 에디터-BPWukongAnim) Equal(Enum) : Jump와 결과 연결
// Jump 스테이트 추가.
(언리얼 에디터-BPWukongAnim) Ground -> Jump
(언리얼 에디터-BPWukongAnim) 우클릭_"machine" -> 스테이트 머신 추가 : "Jump"
(언리얼 에디터-BPWukongAnim) Jump와 출력 애니메이션 포즈 연결
(언리얼 에디터-BPWukongAnim) Ground -> Jump -> Jump
(언리얼 에디터-BPWukongAnim) Entry_드래그 : "Start" -> 디테일-Events-Always Reset on Entry : "체크"
(언리얼 에디터-BPWukongAnim) Start_드래그 : "Loop" -> 디테일-Events-Always Reset on Entry : "체크"
(언리얼 에디터-BPWukongAnim) Loop_드래그 : "Land" -> 디테일-Events-Always Reset on Entry : "체크"
(언리얼 에디터-BPWukongAnim) Land_드래그 : "Recovery" -> 디테일-Events-Always Reset on Entry : "체크"
(언리얼 에디터-BPWukongAnim) Start->Loop-트랜지션 룰 -> 디테일-트랜지션-Automatic Rule Based.. : "체크"
(언리얼 에디터-BPWukongAnim) Land->Recovery-트랜지션 룰 -> 디테일-트랜지션-Automatic Rule Based.. : "체크"
// Start 모션 설정.
(언리얼 에디터-BPWukongAnim) Ground -> Jump -> Jump -> Start
(언리얼 에디터-BPWukongAnim) 에셋 브라우저 : "Jump_Start" -> 디테일-세팅-LoopAnimation : "끔"
(언리얼 에디터-BPWukongAnim) Jump_Start와 출력 애니메이션 포즈 연결
// Loop 모션 설정.
(언리얼 에디터-BPWukongAnim) Ground -> Jump -> Jump -> Loop
(언리얼 에디터-BPWukongAnim) 에셋 브라우저 : "Jump_Apex" -> 디테일-세팅-LoopAnimation : "끔"
(언리얼 에디터-BPWukongAnim) Jump_Apex와 출력 애니메이션 포즈 연결
// Land모션 설정.
(언리얼 에디터-BPWukongAnim) Ground -> Jump -> Jump -> Land
(언리얼 에디터-BPWukongAnim) 에셋 브라우저 : "Jump_Land" -> 디테일-세팅-LoopAnimation : "끔"
(언리얼 에디터-BPWukongAnim) Jump_Land와 출력 애니메이션 포즈 연결
// Recovery모션 설정.
(언리얼 에디터-BPWukongAnim) Ground -> Jump -> Jump -> Recovery
(언리얼 에디터-BPWukongAnim) 에셋 브라우저 : "Jump_Recovery" -> 디테일-세팅-LoopAnimation : "끔"
(언리얼 에디터-BPWukongAnim) Jump_Recovery와 출력 애니메이션 포즈 연결
(언리얼 에디터-BPWukongAnim) Jump_Recovery
(언리얼 에디터-Jump_Recovery) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "ReturnIdle"
// Loop -> Land 연결.
(언리얼 에디터-BPWukongAnim) Loop->Land-트랜지션 룰
(언리얼 에디터-BPWukongAnim) 우클릭_"IsGround"
(언리얼 에디터-BPWukongAnim) IsGround와 결과와 연결
- Start 하는 중에 다른 모션을 할 수 없도록 설정 -
(언리얼 에디터-BPWukongAnim) AnimGraph -> Ground -> LevelStart
(언리얼 에디터-LevelStart) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "PlayerStart"
(C++-PlayerBaseAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h" // CoreMinimal.h를 GameInfo.h로 바꿈.
#include "Animation/AnimInstance.h"
#include "PlayerBaseAnim.generated.h"
UENUM(BlueprintType, Meta = (Bitflags)) // enum문을 사용할 때 사용.
enum class EPlayerBaseAnim : uint8 // uint8로 사용하겠다고 설정.
{
Idle,
Run,
Attack,
Hit,
Jump
};
UCLASS()
class PROJECT1005_API UPlayerBaseAnim : public UAnimInstance
{
GENERATED_BODY()
public:
UPlayerBaseAnim(); // 생성자.
protected:
uint8* BaseAnimType;
// 방향 설정.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EDir"))
uint8 Dir;
// 멈춰있는 지 확인.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool MoveStop;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool AttackEnable;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
uint8 NextAttackIndex;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool IsGround;
uint8 NextAttackMax;
bool NextAttack; // 다음 공격할 것인지.
bool NextAttackEnable; // 다음 공격을 할 것인지 말 것인지.
bool NextAttackInputEnable;
public:
void SetMoveDir(EDir eDir)
{
Dir = (uint8)eDir;
}
public:
// UAnimInstance에 가상함수로 정의되어 있으므로 재정의 하여 사용할 수 있음.
virtual void NativeInitializeAnimation(); // 초기화될 때 사용.
virtual void NativeUpdateAnimation(float DeltaSeconds); // 매 프레임마다 생성.
public:
UFUNCTION() // 노티파이를 호출하기 위해 사용. 언리얼 함수인 것을 알려줌.
void AnimNotify_MoveStop(); // AnimNotify_(노티파이 이름)으로 해야함.
UFUNCTION()
void AnimNotify_AttackEnd(); // AttackEnd 노티파이 추가.
UFUNCTION()
void AnimNotify_InIdle();
UFUNCTION()
void AnimNotify_NextAttackEnd(); // NextAttackEnd 노티파이 추가.
UFUNCTION()
void AnimNotify_ReturnIdle(); // jump후 idle로 돌아가는 노티파이.
UFUNCTION()
void AnimNotify_PlayerStart(); // 플레이어가 시작 모션을 끝내는 노티파이.
public:
void NormalAttack(); // 공격.
void Jump();
public:
virtual void InheritMoveStopNotify();
virtual void InheritAttackEndNotify();
virtual void InheritInIdleNotify();
virtual void InheritNormalAttack();
};
(C++-PlayerBaseAnim.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerBaseAnim.h"
#include "PlayerCharacter.h" // 추가.
UPlayerBaseAnim::UPlayerBaseAnim() // 생성자.
{
Dir = (uint8)EDir::Front; // 기본으로 Front 설정.
MoveStop = true; // 처음에는 멈춰있으므로 true.
AttackEnable = true; // 처음에 공격 가능.
NextAttackEnable = false; // 처음에 다음 공격 불가능하게 설정.
NextAttack = false;
NextAttackInputEnable = false;
NextAttackMax = 0;
NextAttackIndex = 0;
}
void UPlayerBaseAnim::NativeInitializeAnimation() // 초기화될 때 사용.
{
Super::NativeInitializeAnimation();
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle;
}
void UPlayerBaseAnim::NativeUpdateAnimation(float DeltaSeconds) // 매 프레임마다 생성.
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 언리얼에서는 Cast를 사용하여 형변환을 해야 함.
APlayerCharacter* pOwner = Cast<APlayerCharacter>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner)) // IsValid : U오프젝트에 대한 유효성 검사를 해줌. 제대로 된 것인지 확인을 해줘서 더 안전함.
{
UCharacterMovementComponent* pMovement = pOwner->GetCharacterMovement(); // Movement를 얻어옴.
if (IsValid(pMovement))
{
IsGround = pMovement->IsMovingOnGround(); // IsMovingOnGround() : 땅을 밟고 있는 지 판단.
if (IsGround)
{
// Velocity.Size() : 이동속도의 크기
if (pMovement->Velocity.Size() > 0.f) // 0보다 크면 움직임.
{
MoveStop = false; // 이동 중에는 false.
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
*BaseAnimType = (uint8)EPlayerBaseAnim::Run;
}
else // 0이면 움직이지 않음.
{
MoveStop = true; // 멈췄을 때 true.
}
}
}
}
}
void UPlayerBaseAnim::AnimNotify_MoveStop() // 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle; // 동작이 끝나면 Idle로 돌아감.
InheritMoveStopNotify();
}
void UPlayerBaseAnim::AnimNotify_AttackEnd() // 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle; // 동작이 끝나면 Idle로 돌아감.
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
InheritAttackEndNotify();
}
void UPlayerBaseAnim::AnimNotify_InIdle() // 노티파이.
{
AttackEnable = true; // 공격 가능 상태로.
InheritInIdleNotify();
}
void UPlayerBaseAnim::AnimNotify_NextAttackEnd() // NextAttackEnd() 노티파이 추가.
{
if (NextAttack)
{
++NextAttackIndex;
if (NextAttackIndex >= NextAttackMax)
NextAttackIndex = 0;
NextAttack = false;
}
else
{
NextAttackInputEnable = false;
}
}
void UPlayerBaseAnim::AnimNotify_ReturnIdle() // jump후 idle로 돌아가는 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle;
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
}
void UPlayerBaseAnim::NormalAttack() // 공격.
{
if (AttackEnable)
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Attack;
if (NextAttackEnable && NextAttackInputEnable)
{
NextAttack = true;
}
else if(!NextAttackEnable)
AttackEnable = false; // 공격 불가능 상태로.
NextAttackInputEnable = true;
}
InheritNormalAttack();
}
void UPlayerBaseAnim::Jump()
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Jump;
}
void UPlayerBaseAnim::InheritMoveStopNotify()
{
}
void UPlayerBaseAnim::InheritAttackEndNotify()
{
}
void UPlayerBaseAnim::InheritInIdleNotify()
{
}
void UPlayerBaseAnim::InheritNormalAttack()
{
}
(C++-PlayerWukong.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerWukong.h"
#include "WukongAnim.h"
// Sets default values
APlayerWukong::APlayerWukong()
{
// 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;
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); // 카메라 컴포넌트 생성. 생성자에서 생성해야 함.
Arm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Arm")); // Sprint Arm 컴포넌트 생성.
// 셀카봉 같은 느낌.
Arm->SetupAttachment(GetMesh()); // Arm의 부로모 Mesh를 지정.
Camera->SetupAttachment(Arm); // 카메라의 부모로 Arm을 지정.
// 애니메이션 클래스 지정.
static ConstructorHelpers::FClassFinder<UWukongAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Player/BPWukongAnim.BPWukongAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
// 점프의 속도 조절.
// GetCharacterMovement()->JumpZVelocity // JumpZVelocity : 위로 올라가는 속도.
}
// Called when the game starts or when spawned
void APlayerWukong::BeginPlay()
{
Super::BeginPlay(); // 이 액터가 레벨에 입장할 때 배치되고 게임이 시작할 때 딱 한 번만 호출됨.
WukongAnim = Cast<UWukongAnim>(GetMesh()->GetAnimInstance()); // WraithAnim을 받아옴.
}
// Called every frame
void APlayerWukong::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); // 게임이 동작되는 매프레임마다 호출되는 함수.
}
// Called to bind functionality to input
// UInputComponent : 입력받은 것을 연결해서 호출해줄 함수를 연결하는 바인딩 역할을 함.
void APlayerWukong::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent); // 플레이어 컨트롤러가 빙의가 된 후에 호출.
// 언리얼은 유니코드 문자열을 사용하기 때문에 TEXT("")를 사용해야 함.
// this : 어떤 객체를 쓸 것인지.
PlayerInputComponent->BindAxis(TEXT("MoveFront"), this, &APlayerWukong::MoveFront);
PlayerInputComponent->BindAxis(TEXT("MoveSide"), this, &APlayerWukong::MoveSide);
PlayerInputComponent->BindAxis(TEXT("RotationZ"), this, &APlayerWukong::RotationZ);
// EInputEvent::IE_Pressed : 눌렀을 때.
// EInputEvent::IE_Released : 눌렀다가 뗐을 때.
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &APlayerWukong::JumpKey);
PlayerInputComponent->BindAction(TEXT("NormalAttack"), EInputEvent::IE_Pressed, this, &APlayerWukong::NormalAttack);
PlayerInputComponent->BindAction(TEXT("QuickSlot1"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot1);
PlayerInputComponent->BindAction(TEXT("QuickSlot2"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot2);
PlayerInputComponent->BindAction(TEXT("QuickSlot3"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot3);
}
void APlayerWukong::MoveFront(float fScale) // 앞뒤로 이동.
{
if (!bStartAnimation)
return;
// GetActorForwardVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 앞으로, -1이면 뒤로 가게 됨.
AddMovementInput(GetActorForwardVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 앞으로.
WukongAnim->SetMoveDir(EDir::Front);
else if (fScale < 0.f) // 뒤로.
WukongAnim->SetMoveDir(EDir::Back);
}
}
void APlayerWukong::MoveSide(float fScale) // 좌우로 이동.
{
if (!bStartAnimation)
return;
// GetActorRightVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 오른쪽으로, -1이면 왼쪽으로 가게 됨.
AddMovementInput(GetActorRightVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 오른쪽으로.
WukongAnim->SetMoveDir(EDir::Right);
else if (fScale < 0.f) // 왼쪽으로.
WukongAnim->SetMoveDir(EDir::Left);
}
}
void APlayerWukong::RotationZ(float fScale) // 회전.
{
if (!bStartAnimation)
return;
AddControllerYawInput(fScale);
}
void APlayerWukong::JumpKey() // 점프.
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->Jump();
Jump(); // Jump를 지원해줌.
}
void APlayerWukong::NormalAttack() // 공격.
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->NormalAttack();
}
void APlayerWukong::QuickSlot1()
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->Skill1();
}
void APlayerWukong::QuickSlot2()
{
if (!bStartAnimation)
return;
}
void APlayerWukong::QuickSlot3()
{
if (!bStartAnimation)
return;
}
(C++-PlayerCharacter.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h" // CoreMinimal.h를 GameInfo.h로 바꿈.
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"
UCLASS()
class PROJECT1005_API APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerCharacter();
protected:
bool bStartAnimation;
public:
void StartAnimation()
{
bStartAnimation = true;
}
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
(C++-PlayerCharacter.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerCharacter.h"
// Sets default values
APlayerCharacter::APlayerCharacter()
{
// 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;
bStartAnimation = false;
}
// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
'Study > Unreal' 카테고리의 다른 글
[Unreal/정리] 몬스터 클래스 / Spawn시스템 (0) | 2020.10.16 |
---|---|
[Unreal/정리] 무기 장착 (0) | 2020.10.15 |
[Unreal/정리] 연속 공격 (0) | 2020.10.13 |
[Unreal/정리] Player 추가 (0) | 2020.10.12 |
[Unreal/정리] 애니메이션_Attack, Jump (0) | 2020.10.12 |
댓글