본문 바로가기
Unreal/Manual

Unreal FireBall 만들기

by Dev_카페인 2024. 1. 12.
반응형

[Unreal/C++] FireBall 만들기

 

언리얼 엔진에서 Particle System을 이용해 FireBall을 구현한다.

 

 

FireBall로 쓰일 파티클을 준비해줍니다.

액터를 상속받는 클래스를 만들어줍니다.

 

C++에서 필요한 것은 다음과 같습니다.

- 충돌을 체크할 SphereComponent와 

- 파이어 이펙트를 재생할 Particle System Component

- 파이어볼을 움직일 Projectile Movement Component

사실상 에디터에서 준비하는 것이 빠르지만 C++로 작업합니다.

 

USphereComponent* SphereCollider;
UParticleSystemComponent* ParticleSystem;
UProjectileMovementComponent* ProjectileMovement;

 

위 3개 컴포넌트를 .h 파일에 추가하고

생성자에서 해당 컴포넌트를 생성하여 넣어줍니다.

SphereCollider = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
ParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile"));

 

RootComponent를 Sphere 로 설정한 후 ParticleSystem 컴포넌트를 자식으로 붙여줍니다.

SetRootComponent(SphereCollider);
ParticleSystem->SetupAttachment(RootComponent);

 

Sphere 컴포넌트의 충돌체 크기를 조정합니다.

SphereCollider->InitSphereRadius(50);

 

Projectile 컴포넌트로 움직일 대상과 스피드, 중력 등을 설정해줍니다.

ProjectileMovement->SetUpdatedComponent(RootComponent);
ProjectileMovement->InitialSpeed = 1000.0f;
ProjectileMovement->MaxSpeed = 1000.0f;
ProjectileMovement->ProjectileGravityScale = 0.0f;

 

파티클의 레퍼런스를 복사하여 템플릿에 넣어줍니다.

ConstructorHelpers::FObjectFinder<UParticleSystem> particle(L"ParticleSystem'/Game/FXVarietyPack/Particles/P_ky_fireBall.P_ky_fireBall'");
ParticleSystem->SetTemplate(particle.Object);

 

BeginPlay에서 충돌체의 오버랩 이벤트를 연결시켜줍니다.

SphereComponent의 OnComponentBeginOverlap 델리게이트는 PrimitiveComponent.h에 정의되어 있습니다.

SphereComponent가 Primitive 컴포넌트를 상속받고 있으므로 사용할 수 있습니다.

AddDynamic으로 생성한 함수를 연결해줍니다.

SphereCollider->OnComponentBeginOverlap.AddDynamic(this, &AFireBall::OnComponentBeginOverlap);

이 델리게이트는 OnComponentBeginOverlap이 정의되어 있는 시그니처를 따라 추적해보면 확인할 수 있습니다.

OnComponentBeginOverlap 뒤에 있는 UPrimitiveComponent* 부터 복사하여 사용하되 중간중간에 필요없는 콤마(',')를 삭제해 사용합니다.

 

연결된 충돌 함수는 제외할 대상이 필요합니다.

생성되자마자 생성한 주체와 충돌될 가능성이 있기 때문에 GetOwner()를 제외해주고 필요하다면 Tags를 이용해 충돌 대상을 제외시켜줍니다.

 

그 외에는 충돌 시 자기 자신을 삭제해 준다면 베스트입니다.

if (OtherActor == GetOwner()) return;
UGameplayStatics::ApplyDamage(OtherActor, 10, GetOwner()->GetInstigatorController(), this, UDamageType::StaticClass());
Destroy();

그리고 Projectile에는 방향 설정이 안되어 있기 때문에 Spawn시 방향을 설정해 줄 수 있는 함수도 준비합니다.

 

void AFireBall::SetDirection(FVector InDirection)
{
ProjectileMovement->Velocity = InDirection * ProjectileMovement->InitialSpeed;
}

 

아래에 전체 코드를 확인할 수 있습니다.

 

 

최종 코드

// FireBall.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FireBall.generated.h"

class USphereComponent;
class UParticleSystemComponent;
class UProjectileMovementComponent;

UCLASS()
class MAINPROJECT_API AFireBall : public AActor
{
	GENERATED_BODY()
	
public:	
	AFireBall();

protected:
	virtual void BeginPlay() override;

public :
	UFUNCTION()
		void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

public:
	void SetDirection(FVector InDirection);

private :
	UPROPERTY(VisibleDefaultsOnly)
		USphereComponent* SphereCollider;

	UPROPERTY(VisibleDefaultsOnly)
		UParticleSystemComponent* ParticleSystem;

private :
	UPROPERTY(VisibleDefaultsOnly)
		UProjectileMovementComponent* ProjectileMovement;
};

 

// FireBall.cpp

#include "Enemy/Weapons/FireBall.h"

#include "Kismet/GameplayStatics.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
#include "Particles/ParticleSystemComponent.h"

AFireBall::AFireBall()
{
	Tags.Add("Enemy");

	//SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent")));
	SphereCollider = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
	ParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
	ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile"));

	SetRootComponent(SphereCollider);
	ParticleSystem->SetupAttachment(RootComponent);

	SphereCollider->InitSphereRadius(50);

	// Projectile 설정
	ProjectileMovement->SetUpdatedComponent(RootComponent);
	ProjectileMovement->InitialSpeed = 1000.0f;
	ProjectileMovement->MaxSpeed = 1000.0f;
	ProjectileMovement->ProjectileGravityScale = 0.0f;

	ConstructorHelpers::FObjectFinder<UParticleSystem> particle(L"ParticleSystem'/Game/FXVarietyPack/Particles/P_ky_fireBall.P_ky_fireBall'");
	ParticleSystem->SetTemplate(particle.Object);
}

void AFireBall::BeginPlay()
{
	Super::BeginPlay();
	
	SphereCollider->OnComponentBeginOverlap.AddDynamic(this, &AFireBall::OnComponentBeginOverlap);
}

void AFireBall::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor == GetOwner()) return;

	UGameplayStatics::ApplyDamage(OtherActor, 10, GetOwner()->GetInstigatorController(), this, UDamageType::StaticClass());
	
	Destroy();
}

void AFireBall::SetDirection(FVector InDirection)
{
	ProjectileMovement->Velocity = InDirection * ProjectileMovement->InitialSpeed;
}

 

컴파일을 한 후 FireBall을 상속받는 블루프린트 클래스를 만들어 확인합니다.

레퍼런스를 복사하여 필요에 따라 사용합니다.

여기까지 작업이 완료되었다면, 공격하는 대상에서 생성 후 앞으로 날아갈 수 있게 합니다.

TSubclassOf<AFireBall> FireBall; // 헤더파일에 선언
// 생성자에서 정의
ConstructorHelpers::FClassFinder<AFireBall> fireBall(L"Blueprint'/Game/Enemies/Weapons/FireBall/BP_FireBall.BP_FireBall_C'");
FireBall = fireBall.Class;

 

void AWizard::Attack()
{
	FTransform transform(GetActorLocation());
	AFireBall* fireBall = GetWorld()->SpawnActorDeferred<AFireBall>(FireBall, transform, this, this, ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
	if (fireBall == nullptr) return;

	FVector destination =  target->GetActorLocation();	// 필요에 따라 정의
	FVector direction = (destination - location).GetSafeNormal();

	fireBall->SetDirection(direction);
	fireBall->FinishSpawning(fireBall->GetTransform());
}

 

구현은 몽타주 Animation Notify를 이용하거나 단순히 키를 바인딩하여 Attack 함수만 호출해주면 됩니다.

반응형