24.10.17 MyCharacter의 수정사항입니다.
MyCharacter.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"
// 공격 애니메이션이 끝났는지 확인
DECLARE_MULTICAST_DELEGATE(FOnAttackEndDelegate);
UCLASS()
class EDR_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// 받는 데미지 처리 함수
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;
UPROPERTY(BluePrintReadWrite)
float hp = 100.0f;
// 보스 캐릭터의 공격 데미지 설정 변수
UPROPERTY(BluePrintReadWrite)
float AttackDamage;
UPROPERTY()
TObjectPtr<class UAnimMontage> AttackMontage;
UPROPERTY()
TObjectPtr<class UAnimMontage> DeathMontage;
// 애니메이션 재생을 위해 공격중인지 확인
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
bool IsAttacking;
// 애니메이션 인스턴트 객체
UPROPERTY()
class UAnim_EDR_AnimInstance* EDRAnim;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UPROPERTY(BluePrintReadWrite)
bool Death = false;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION(BlueprintPure, category = "Player")
float GetHp() { return hp; }
UFUNCTION(BlueprintCallable, category = "Player")
virtual void UpdateHP(float NewHP);
UFUNCTION(BlueprintCallable, category = "Player")
virtual void IsDeath();
// 공격 함수
virtual void Attack();
FOnAttackEndDelegate OnAttackEnd;
UFUNCTION()
void OnAttackMontageEnded(UAnimMontage* Montage, bool bInterrupted);
private:
};
반응형
MyCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyCharacter.h"
#include "Engine/World.h"
#include "Anim_EDR_AnimInstance.h"
#include "TimerManager.h"
// Sets default values
AMyCharacter::AMyCharacter()
{
// 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;
IsAttacking = false;
}
// Called when the game starts or when spawned
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
// 공격 애니메이션 종료
void AMyCharacter::OnAttackMontageEnded(UAnimMontage* Montage, bool bInterrupted)
{
if (!IsAttacking)
{
return;
}
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("end play"));
IsAttacking = false;
OnAttackEnd.Broadcast();
}
// 사망 애니메이션
void AMyCharacter::IsDeath()
{
// 이미 죽어있으면 애니메이션 실행 안함
if (Death)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("Death true"));
return;
}
// 애니메이션 몽타주 실행
PlayAnimMontage(DeathMontage);
Death = true;
}
void AMyCharacter::UpdateHP(float NewHP)
{
hp += NewHP;
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, FString::Printf(TEXT("UpdateHP() - %s HP : %f"), *GetName(), hp));
}
void AMyCharacter::Attack()
{
// Death가 true 일경우 공격 애니메이션 정지
if (Death)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("is Death true"));
return;
}
// 공격중일 경우 애니메이션 정지
if (IsAttacking)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("is attacking true"));
return;
}
EDRAnim = Cast<UAnim_EDR_AnimInstance>(GetMesh()->GetAnimInstance());
if (nullptr == EDRAnim)
{
return;
}
// 애니메이션 몽타주 실행
PlayAnimMontage(AttackMontage, 1.0f);
IsAttacking = true;
EDRAnim->OnMontageEnded.AddDynamic(this, &AMyCharacter::OnAttackMontageEnded);
}
// 데미지 받는 함수
float AMyCharacter::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (Death)
{
return Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
}
// 입은 데미지 만큼 hp 차감
UpdateHP(-DamageAmount);
// hp가 0이 되었을경우 사망 함수 호출
if (this->hp <= 0)
{
this->hp = 0;
IsDeath();
}
return Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
}
MyCharacter에 애니메이션 몽타주를 저장하는 변수인 AttackMontage와 DeathMontage을 만들어두었고, 이를 상속받은 클래스에서 몽타주 경로를 저장하도록 하였습니다.
공격중일때 사망하면 사망 애니메이션이 출력되지 않고 공격 애니메이션이 계속 출력 되었었는데,
Death가 true 일경우 return 하도록 하여 해결하였습니다.
상속할때 주의할 점은 상속받을 함수의 virtual 선언과 상속 받을 때 override를 잊지 않는 것 입니다.
사망 애니메이션이 출력된 모습입니다.
테스트 영상
공격중일때도 hp가 0이 되면 사망 애니메이션 출력 합니다.
'Unreal Engine 5 > EDR_Project' 카테고리의 다른 글
EDR_Project / AnimInstance (2) Notify (0) | 2024.10.20 |
---|---|
EDR_Project / TurnToTarget, 회전 부드럽게 (0) | 2024.10.18 |
EDR_Project / EDR_Boss_Giant (0) | 2024.10.17 |
EDR_Project / AnimInstance (1) (0) | 2024.10.17 |
EDR_Project / Attack (10) | 2024.10.17 |