본문 바로가기
Unreal Engine5/KDT 2024

[UE5 KDT2024] 27. 몬스터 폰 제작

by 유잉유잉유잉 2025. 3. 11.
728x90

 

1. MonsterBase 클래스를 만들어보자 

 

1) Actors폴더/pawn 상속 / MonsterBase  클래스 생성

 

2) 초기화시 캡슐,  메시 컬리전 설정 등 초기화 

header

#include "EngineMinimal.h"
...
protected:
	UPROPERTY( EditAnywhere, BlueprintReadWrite )
	USkeletalMeshComponent* mMesh;

	UPROPERTY( EditAnywhere, BlueprintReadWrite )
	UCapsuleComponent* mCapsule;

생성자

AMonsterBase::AMonsterBase()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	mMesh		= CreateDefaultSubobject<USkeletalMeshComponent>(L"Mesh");
	mCapsule	= CreateDefaultSubobject<UCapsuleComponent>(L"Collision");

	SetRootComponent( mCapsule );
	mMesh->AttachToComponent( mCapsule, FAttachmentTransformRules::KeepRelativeTransform );
	mMesh->SetCollisionEnabled( ECollisionEnabled::NoCollision );
}

 

2) 블프/Actors 폴더에 블루프린트 추가, MonsterBase 상속 ->  BP_Orc

메시 설정, 캡슐 크기 설정, 회전  

3가지 보기좋게 설정해주기.

 

3) 무기 추가해보기

(1) Maul_Sm복사 후 추가 후 스태틱 메시 컴포넌트(Maul_SM)추가, 이름 Weapon으로 변경  

(2) 매쉬 자식으로 이동

 

 

(3) 무기 쥐어줄 위치 찾기. 메쉬의 스켈레톤 에디터 가서 소켓 위치 찾기

 

 

(4) Weapon 선택 후 디테일창에서 부모소켓에 폴더모양 눌러서 무기소켓 이름 넣기  

ㄴ 매시에서 소켓 아이콘 가진 애 이름 찾아서 넣어주기 

웨폰이 매시 아래있어야 적용됨.. 캡슐 바로 아래 있을 경우 적용이 안된다..

 

 

4) 애니메이션 추가하기 

애니메이션 블루프린트 추가 - 스켈레톤 선택 - 부모클래스로 AnimBase 선택 - BPA_AnimOrc 추가

 

 

5) BPA_AnimOrc에디터에 애니메이션 연결

  • idle, run 애니 추가 후 루프 선택 

 

6) BP_Orc에디터에서 디테일창 - 애님클래스에 BPA_AnimOrc 연결

여기까지 진행하면 오크 몬스터가 무기를 들게된다.



 


 

 

2. 몬스터에 애니메이션을 적용시키자

 

1) Define.h EAnimType에 

hit와 die 추가 

UENUM( BlueprintType )
enum class EAnimType : uint8
{
	ANIMTYPE_IDLE	UMETA( DisplayName = "Idle" ),
	ANIMTYPE_WALK	UMETA( DisplayName = "Walk" ),
	ANIMTYPE_HIT	UMETA( DisplayName = "Hit" ),
	ANIMTYPE_DIE	UMETA( DisplayName = "Die" ),
	ANIMTYPE_END	UMETA( DisplayName = "End" ),
};

 

2) BPA_AnimOrc 에디터와서 Blend Pose에 Hit, Die추가 및 애니 연결 

(1) 오크 애님에 해당 애니 추가 및 연결 

 

(2) 애니메이션 추가시, Blend Poses 추가 후 활성 열거형값을 mAnimType으로 설정해주기



 


 

 

3. 몬스터가 맞을 때 데미지를 입도록 변경해보자 

 

▶️ApplyDamage() 

: 데미지 주는 함수 

 - AActor* DamagedActor : 데미지 받을 액터

 - float BaseDamage : 데미지 양

 - AController* EventInstigator : 데미지 주는 컨트롤러

 - AActor* DamageCauser: 데미지 주는 액터

 - TSubclassOf<UDamageType> DamageTypeClass) : 적용할 데미지 타입 

uint32 bCausedByWorld:1; // 지형에 의한 ex) 용암뎀

ex) 

UGameplayStatics::ApplyDamage( hit.GetActor(), 1, GetController(), this, UDamageType::StaticClass());

 

 

▶️TakeDamage() 

: 데미지 받는 함수 

- Damage : 받은 데미지 양

- DamageEvent : 데미지 종류. 방사형인지 일점사인지 등등 

- EventInstigator : 데미지를 준 컨트롤러

- DamageCauser : 데미지를 준 액터 

ex) 

virtual float TakeDamage( float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser );

 

 

1) playerKnight에서 공격할 때 데미지 주는 함수 추가

void APlayerKnight::AttackCollision_Server_Implementation()
{
	...
	// 충돌된 물체가 있다면 
	if ( collision )
	{
		// Ranged For
		for ( const FHitResult& hit : result )
		{
			UGameplayStatics::ApplyDamage( hit.GetActor(), 1, GetController(), this, UDamageType::StaticClass() );

			// 서버에 연결된 모든 클라이언트들에게 이펙트 출력 
			SpawnEffect_MultiCast( hit.Location );
		}
	}
}

 

 

2) 몬스터 타격 당하는 함수 추가 

 

▶️ApplyDamage() 내부를 보면 

float UGameplayStatics::ApplyDamage(AActor* DamagedActor, float BaseDamage, AController* EventInstigator, AActor* DamageCauser, TSubclassOf<UDamageType> DamageTypeClass)
{
	if ( DamagedActor && (BaseDamage != 0.f) )
	{
		// make sure we have a good damage type
		TSubclassOf<UDamageType> const ValidDamageTypeClass = DamageTypeClass ? DamageTypeClass : TSubclassOf<UDamageType>(UDamageType::StaticClass());
		FDamageEvent DamageEvent(ValidDamageTypeClass);

		return DamagedActor->TakeDamage(BaseDamage, DamageEvent, EventInstigator, DamageCauser);
	}

	return 0.f;
}

ㄴ> 데미지 입은 액터에 TakeDamage를 호출하니까 

몬스터 클래스에서 TakeDamage 함수를 재정의해서 데미지를 먹도록 처리해주자.

 

MonsterBase.h 

TakeDamage는 APawn에있는 TakeDamage()에서 인자 보고 가져와서 오버라이드해주기 

protected:
..
	UPROPERTY()
	int32 mHP;
..
public:
	virtual float TakeDamage ( float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser ) override;



AMonsterBase::AMonsterBase()
{
..
mHP = 5;
}

float AMonsterBase::TakeDamage( float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser )
{
	Super::TakeDamage( Damage, DamageEvent, EventInstigator, DamageCauser );
	
	if ( mHP > 0 )
		mHP -= Damage;

	return Damage;
}

=> 브레이크포인트 걸고 실행하면 데미지 함수들 잘 들어옴



 


 

 

4. 몬스터 타격 애니메이션 실행 서버 함수 호출 추가 

MonsterBase.h

public :
..
	UFUNCTION(BlueprintCallable, Server, Reliable )
	void ChangeAnimMonster_Server(EAnimType AnimType);
	void ChangeAnimMonster_Server_Implementation(EAnimType AnimType);

	UFUNCTION( BlueprintCallable, NetMulticast, Reliable )
	void ChangeAnimMonster_NetMulticast( EAnimType AnimType );
	void ChangeAnimMonster_NetMulticast_Implementation( EAnimType AnimType );
float AMonsterBase::TakeDamage( float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser )
{
	Super::TakeDamage( Damage, DamageEvent, EventInstigator, DamageCauser );
	
	if ( mHP > 0 )
	{
		mHP -= Damage;

		if ( mHP > 0 )
			ChangeAnimMonster_Server( EAnimType::ANIMTYPE_HIT );
		else
			ChangeAnimMonster_Server( EAnimType::ANIMTYPE_DIE );
	}

	return Damage;
}

void AMonsterBase::ChangeAnimMonster_Server_Implementation( EAnimType AnimType )
{
	ChangeAnimMonster_NetMulticast( AnimType );
}

void AMonsterBase::ChangeAnimMonster_NetMulticast_Implementation( EAnimType AnimType )
{
	UAnimBase* anim = Cast<UAnimBase>( mMesh->GetAnimInstance() );
	if ( !IsValid( anim ) )
		return;

	anim->SetAnimType( AnimType );
}

 

CreateDefaultSubobject 생성시 뒤에 text안붙여도 된다. 지금은 룰이다 생각하고 넣는중이다.


728x90

댓글