- 플레이어 공격 판정
- 플레이어의 기본 공격 시 SweepTrace를 통해 공격 성공/실패 체크하기
Anim Notify
- 애니메이션 재생 중 특정한 이벤트를 발생시키는데 사용되는 기능
- 애니메이션 시퀀스 내에서 발생하는 특정 지점에서 호출되는 사용자 정의 이벤트라고 볼 수 있다.
"AnimNotify" 클래스를 상속받는 "AnimNotify_MMBaseAttackCheck" 클래스를 추가해주도록 하겠습니다.
BasicComboAttack 몽타주에서 생성한 노티파이를 추가해주도록 합니다.
AnimNotify_MMBaseAttackCheck 클래스를 작성해주도록 하겠습니다.
AnimNotify_MMBaseAttackCheck Class
- 노티파이 이벤트가 들어온 경우 실행할 로직을 추가해주도록 합니다.
- 호출되어야 하는 함수를 오버라이드 해준 후 구현해주도록 하겠습니다.
// AnimNotify_MMBaseAttackCheck Header
UCLASS()
class MYSTICMAZE_API UAnimNotify_MMBaseAttackCheck : public UAnimNotify
{
GENERATED_BODY()
protected:
virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference);
};
// AnimNotify_MMBaseAttackCheck Cpp
void UAnimNotify_MMBaseAttackCheck::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if (MeshComp)
{
// TODO : 플레이어 클래스의 AttackCheck 실행
}
}
- 언리얼에서 제공하는 Trace 함수를 통해 체크하도록 하겠습니다.
- Sphere 모형으로 체크할 예정이므로 Sweep을 사용합니다.
- 범위 내에 있는 모든 물체를 탐지할 예정이므로 Multi를 사용합니다.
- 즉, MMAction채널을 사용한 SweepMultiByChannel를 진행하도록 하겠습니다.
// MMPlayerCharacter Header
// Attack Section
public:
void BaseAttackCheck();
// MMPlayerCharacter CPP
void AMMPlayerCharacter::BaseAttackCheck()
{
// 충돌 결과를 반환하기 위한 배열
TArray<FHitResult> OutHitResults;
// 공격 반경
float AttackRange = 100.0f;
// 공격 체크를 위한 구체의 반지름
float AttackRadius = 50.0f;
// 충돌 탐지를 위한 시작 지점 (플레이어 현재 위치 + 전방 방향 플레이어의 CapsuleComponent의 반지름 거리)
FVector Start = GetActorLocation() + (GetActorForwardVector() * GetCapsuleComponent()->GetScaledCapsuleRadius());
// 충돌 탐지 종료 지점 (시작지점 + 전방 방향의 공격 거리)
FVector End = Start + (GetActorForwardVector() * AttackRange);
// 파라미터 설정하기 (트레이스 태그 : Attack, 복잡한 충돌 처리 : false, 무시할 액터 : this)
FCollisionQueryParams Params(SCENE_QUERY_STAT(Attack), false, this);
bool bHasHit = GetWorld()->SweepMultiByChannel(
OutHitResults,
Start,
End,
FQuat::Identity,
CHANNEL_MMACTION,
FCollisionShape::MakeSphere(AttackRadius),
Params
);
if (bHasHit)
{
// TODO : 데미지 전달
}
// Capsule 모양의 디버깅 체크
FVector CapsuleOrigin = Start + (End - Start) * 0.5f;
float CapsuleHalfHeight = AttackRange * 0.5f;
FColor DrawColor = bHasHit ? FColor::Green : FColor::Red;
DrawDebugCapsule(GetWorld(), CapsuleOrigin, CapsuleHalfHeight, AttackRadius, FRotationMatrix::MakeFromZ(GetActorForwardVector()).ToQuat(), DrawColor, false, 3.0f);
}
// AnimNotify_MMBaseAttackCheck Cpp
#include "Animation/AnimNotify_MMBaseAttackCheck.h"
#include "Character/MMPlayerCharacter.h"
void UAnimNotify_MMBaseAttackCheck::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if (MeshComp)
{
// 플레이어 클래스의 BaseAttackCheck 실행
AMMPlayerCharacter* Player = Cast<AMMPlayerCharacter>(MeshComp->GetOwner());
if (Player)
{
Player->BaseAttackCheck();
}
}
}
의존성
- 한 요소가 다른 요소에 종속되어 있음을 나타냅니다.
- 클래스 A가 클래스 B를 사용한다면 클래스 A는 클래스 B에 대해 의존하고 있다고 할 수 있습니다.
현재 생성한 MMBaseAttackCheck클래스는 MMPlayerCharacter 클래스의 헤더를 참조하고 있습니다.
- 인터페이스를 사용해 클래스 간의 의존성을 줄여보도록 하겠습니다.
// MMAnimationAttackInterface Header
class MYSTICMAZE_API IMMAnimationAttackInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
// 기본 공격 성공/실패 여부 체크
virtual void BaseAttackCheck() = 0;
};
// AMMPlayerCharacter Header
#include "CoreMinimal.h"
#include "Character/MMCharacterBase.h"
#include "InputActionValue.h"
#include "Interface/MMAnimationAttackInterface.h"
#include "MMPlayerCharacter.generated.h"
/**
*
*/
UCLASS()
class MYSTICMAZE_API AMMPlayerCharacter : public AMMCharacterBase, public IMMAnimationAttackInterface
{
...
// Attack Section
protected:
virtual void BaseAttackCheck() override;
}
// UAnimNotify_MMBaseAttackCheck Cpp
#include "Animation/AnimNotify_MMBaseAttackCheck.h"
#include "Interface/MMAnimationAttackInterface.h"
void UAnimNotify_MMBaseAttackCheck::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if (MeshComp)
{
// 공격 성공 여부 체크
IMMAnimationAttackInterface* AttackPawn = Cast<IMMAnimationAttackInterface>(MeshComp->GetOwner());
if (AttackPawn)
{
AttackPawn->BaseAttackCheck();
}
}
}