[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 함수만 호출해주면 됩니다.
'Unreal > Manual' 카테고리의 다른 글
Unreal 캐릭터 대쉬, 구르기에 사용할 수 있는 LaunchCharacter (0) | 2024.01.14 |
---|---|
Unreal 플레이어를 바라보는 방향으로 적 회전 (0) | 2024.01.14 |
Unreal 적이나 목적지의 방향 구하기 (0) | 2024.01.12 |
Unreal Mesh Socket 위치에서 SpawnActorDeferred 하기 (0) | 2024.01.12 |
Unreal Particle Object 가져오기 (0) | 2024.01.11 |