
오늘은 Enemy 클래스를 만들어보자. Character를 상속받는 Enemy 클래스를 만들어주자.

이 Enemy 클래스는 무기가 Pawn 으로 지정된 객체의 성질에는
Collision Enabled 하기 때문에 World Dynamic로 설정해주어야하고 보이는 것에 Collision 했을 때 막혀야한다.
그리고 카메라와의 충돌은 무시해야 하고 Hit 이벤트를 처리해줄 수 있게 오버랩 이벤트는 True로 설정해주자.
Enemy.cpp
#include "Enemy/Enemy.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CapsuleComponent.h"
AEnemy::AEnemy()
{
	PrimaryActorTick.bCanEverTick = true;
	GetMesh()->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
	GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
	GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
	GetMesh()->SetGenerateOverlapEvents(true);
	GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
}
void AEnemy::BeginPlay()
{
	Super::BeginPlay();
	
}
void AEnemy::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}
void AEnemy::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
}
이렇게 하고 컴파일 해준다음에 언리얼에서 이 Enemy 클래스를 바탕으로 블루프린트 클래스를 생성해주자.

여기에 사용할 매쉬를 Mixamo에서 다운받아주자

이 캐릭터가 피격시에 피격 애니메이션을 출력해줘야하는데 이때 캐릭터가 피격에 따라 움직일 수 도 있다.
이때 애니메이션 자체에 매쉬를 움직이는 애니메이션이 있는데 이를 Root Motion Animations라고 한다.
이 Root Motion Animations는 루트라는 최상단 뼈 노드를 통해 움직임을 제어한다. 이를 위해 만약 Root 노드가 없다면 블렌더와 같은 편집프로그램으로 만들어줘야한다.
이제 여기서 Hit모션이 기능하도록 만들어보자
우선 전에 만들어둔 HitInterface를 활용하자. Enemy클래스에서 이 인터페이스를 상속받아서 이 인터페이스의 가상함수인 GetHit을 구현하도록 하면 된다.
이때 매개변수로 Const 값을 넘겨주어서 복사가 일어나지 않게 하여 참조의 수를 줄일 수 있다.
Enemy.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interfaces/HitInterface.h"
#include "Enemy.generated.h"
UCLASS()
class SLASH_API AEnemy : public ACharacter, public IHitInterface
{
	GENERATED_BODY()
public:
	
	AEnemy();
	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	virtual void GetHit(const FVector& ImpactPoint) override;
protected:
	virtual void BeginPlay() override;
};
Enemy.cpp
void AEnemy::GetHit(const FVector& ImpactPoint)
{
	DRAW_SPHERE(ImpactPoint);
}
이렇게 만들고 난 다음 Weapon에서 GetHit을 호출하면 되는데 이때 Cast를 통해 부딪힌 객체를 가져와서 사용하면 된다.
Weapon.cpp
void AWeapon::OnBoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	const FVector Start = BoxTraceStart->GetComponentLocation();
	const FVector End = BoxTraceEnd->GetComponentLocation();
	TArray<AActor*> ActorsToIgnore;
	ActorsToIgnore.Add(this);
	//충돌 결과
	FHitResult BoxHit;
	UKismetSystemLibrary::BoxTraceSingle(
		this,
		Start,
		End,
		FVector(5.f, 5.f, 5.f),
		BoxTraceStart->GetComponentRotation(),
		ETraceTypeQuery::TraceTypeQuery1,
		false,
		ActorsToIgnore,		//무시할거
		EDrawDebugTrace::ForDuration,
		BoxHit,
		true		//자신무시
	);
	if (BoxHit.GetActor())
	{
		IHitInterface* HitInterface = Cast<IHitInterface>(BoxHit.GetActor());
		if (HitInterface)
		{
			HitInterface->GetHit(BoxHit.ImpactPoint);
		}
	}
}
이렇게 해주면 GetHit이 잘 작동하는 것을 볼 수 있다.

이것을 활용해서 어느부분에 맞는지에 따라 다른 애니메이션이 출력되도록 할 것이다.
이를 위하여 애니메이션 몽타주를 만들고 몽타주 섹션을 나눈 다음 이 몽타주 섹션을 통해 각각 다른 애니메이션이 재생되도록 하자.

이때 주의해야할 점은 애니메이션 블루프린트 클래스에서 Default Slot을 가져다가 사용해야 정상적으로 활용할 수 있다.
이를 위해 애니메이션 블루 프린트를 만들어주자.

다음과 같이 해주면 Idle 애니메이션에서 몽타주섹션에 따라 다른 애니메이션이 출력된다.
그리고 적 블루프린트에 들어가서 애니메이션 모드를 Animation BluePrint모드로 설정한 뒤 만들어둔 애니메이션 블루프린트를 할당해준다.
이렇게 해주면 기본 Idle 애니메이션이 동작하게 된다.

이렇게 해준 다음에 코드로 돌아가서 이 몽타주섹션이 재생되게 하면 되는데 적에 캐릭터가 칼을 착용할 때 했던 방법을 따라하면 된다.
우선 우리가 만든 애니메이션 몽타주를 블루프린트에 할당할 수 있게 UAnimMontage 전방선언을 해준 다음 변수로 선언해준다.
그리고 호출되는 이름에 따라 몽타주의 섹션을 재생해주는 함수를 추가하면 된다. 지금은 기본으로 왼쪽에서 맞았을 때의 몽타주 섹션만 출력되게 하자.
Enemy.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interfaces/HitInterface.h"
#include "Enemy.generated.h"
class UAnimMontage;
UCLASS()
class SLASH_API AEnemy : public ACharacter, public IHitInterface
{
	GENERATED_BODY()
private:
	/**
	애니메이션 몽타주
	*/
	UPROPERTY(EditDefaultsOnly, Category = Montages)
	UAnimMontage* HitReactMontage;
protected:
	virtual void BeginPlay() override;
	/**
	애니메이션 몽타주
	*/
	void PlayHitReactMontage(const FName& SectionName);
}
Enemy.cpp
void AEnemy::PlayHitReactMontage(const FName& SectionName)
{
	UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
	if (AnimInstance && HitReactMontage)
	{
		AnimInstance->Montage_Play(HitReactMontage);
		AnimInstance->Montage_JumpToSection(SectionName, HitReactMontage);
	}
}
그리고 주의해야할 점은 애니메이션에서 애니메이션 디테일에 루트모션 활성화를 켜두어야 맞았을 때 원래자리로 돌아오지 않는다. 이때 루트모션은 Skeleton이 루트를 기준으로 설정되어 있을 때만 가능하다.

이렇게 하고 적을 공격해보면 기본위치에서 피격 애니메이션을 출력한 뒤 옆으로 이동되는 것을 볼 수 있다.

'게임공부 > Unreal Engine' 카테고리의 다른 글
| [Unreal Engine][C++]15. Breakable Actors (0) | 2024.12.31 | 
|---|---|
| [Unreal Engine][C++]14. Hit React (3) | 2024.12.27 | 
| [Unreal Engine][C++]12. Weapon Class(Attacking) (1) | 2024.08.16 | 
| [Unreal Engine][C++]11. Attacking (1) | 2024.08.04 | 
| [Unreal Engine][C++]10. The Weapon Class (1) | 2024.07.29 |