Unreal 5/FPS Shooting

2. [Unreal 5 / C++] 발사체 구현 하기

돼지표 2025. 1. 2. 19:56

 

발사체 액터 클래스 추가

이번 시간에는 슈팅 시 생성될 발사체를 구현해보자. 먼저 액터를 상속받는 Projectile 클래스를 추가한다.

 


Projectile 클래스 헤더 구성

발사체의 주요 구성 요소는 다음과 같다:

  • SphereComponent: 발사체의 충돌 처리.
  • ProjectileMovementComponent: 발사체의 이동 처리.
  • StaticMeshComponent: 발사체의 모습 정의.
  • ParticleSystem: 발사체 충돌 시 발생할 이펙트 정의.
#pragma once

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

UCLASS()
class PROJECT_4_API AProjectile : public AActor
{
    GENERATED_BODY()

public:
    AProjectile();

protected:
    virtual void BeginPlay() override;

public:
    virtual void Tick(float DeltaTime) override;

    USphereComponent* CollisionComponent;
    UProjectileMovementComponent* ProjectileMovementComponent;
    UStaticMeshComponent* ProjectileMeshComponent;
    UParticleSystem* ImpactEffect;

    UFUNCTION()
    void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);

	void ShootInDirection(const FVector& ShootDirection, const uint32 Speed);
};

컴포넌트 초기화

1. CollisionComponent 초기화

CollisionComponent는 발사체의 충돌 처리를 담당한다. 아래와 같이 설정한다:

CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
CollisionComponent->InitSphereRadius(15.0f);
CollisionComponent->SetCollisionProfileName(TEXT("BlockAll"));
CollisionComponent->SetNotifyRigidBodyCollision(true); // Enable hit events
RootComponent = CollisionComponent;

2. ProjectileMovementComponent 초기화

발사체의 이동을 처리하며, 낙차 효과를 추가하려면 ProjectileGravityScale 값을 증가시키면 된다.

ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;
ProjectileMovementComponent->ProjectileGravityScale = 0.0f;

3. ProjectileMeshComponent 초기화

발사체의 외형을 정의하며, 메쉬와 재질을 설정한다.

ProjectileMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ProjectileMeshComponent"));
static ConstructorHelpers::FObjectFinder<UStaticMesh> Mesh(TEXT("'/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere'"));
if (Mesh.Succeeded())
{
    ProjectileMeshComponent->SetStaticMesh(Mesh.Object);
}
static ConstructorHelpers::FObjectFinder<UMaterial> Material(TEXT("'/Game/StarterContent/Materials/M_Metal_Burnished_Steel.M_Metal_Burnished_Steel'"));
if (Material.Succeeded())
{
    UMaterialInstanceDynamic* ProjectileMaterialInstance = UMaterialInstanceDynamic::Create(Material.Object, ProjectileMeshComponent);
    ProjectileMeshComponent->SetMaterial(0, ProjectileMaterialInstance);
}
ProjectileMeshComponent->SetRelativeScale3D(FVector(0.09f, 0.09f, 0.09f));
ProjectileMeshComponent->SetupAttachment(RootComponent);

4. ParticleSystem 초기화

발사체 충돌 시 나타날 이펙트를 설정한다.

static ConstructorHelpers::FObjectFinder<UParticleSystem> Particle(TEXT("'/Game/ParagonMurdock/FX/Particles/Abilities/SpreadShot/FX/P_SpreadShotImpact.P_SpreadShotImpact'"));
if (Particle.Succeeded())
{
    ImpactEffect = Particle.Object;
}

 

에셋 경로는 "레퍼런스 복사" 기능을 이용해 추출할 수 있다.

 


발사체 수명 및 이벤트 바인딩

CollisionComponent에 충돌 이벤트를 등록하고, 발사체의 생존 시간을 5초로 제한해 리소스를 절약한다.

CollisionComponent->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
InitialLifeSpan = 5.0f;

 


OnHit 이벤트 함수 구현

발사체가 움직일 수 있는 객체와 충돌 시 해당 객체를 밀어내고, 명중 이펙트를 생성한 후 발사체를 파괴한다.

void AProjectile::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
    UE_LOG(LogTemp, Display, TEXT("On hit bullet"));

    if (OtherActor != this && OtherComponent->IsSimulatingPhysics())
    {
        OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 100.0f, Hit.ImpactPoint);
    }

    // Spawn impact effect
    if (ImpactEffect)
    {
        UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());
    }

    // Destroy the projectile
    Destroy();
}

 


ShootInDirection 함수

발사체의 초기 방향과 속도를 설정한다.

void AProjectile::ShootInDirection(const FVector& ShootDirection, const uint32 Speed)
{
    ProjectileMovementComponent->InitialSpeed = Speed;
    ProjectileMovementComponent->MaxSpeed = Speed;
	ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}

발사체 스폰 및 방향 설정

Fire 함수에서 Projectile 객체를 스폰하고, 방향을 설정하는 코드는 다음과 같다:

FActorSpawnParameters SpawnParams;
AProjectile* Projectile = GetWorld()->SpawnActor<AProjectile>(AProjectile::StaticClass(), MuzzleLocation, ShootDirection.Rotation(), SpawnParams);
if (Projectile)
{
    Projectile->ShootInDirection(ShootDirection, WeaponData->ProjectileSpeed);
}

 


이상으로 발사체 액터의 구현과 초기 구성에 대해 알아보았다. 다음 시간에는 동적인 크로스헤어, 반동, 그리고 탄착군에 대해 다뤄보도록 하자.