[UE5] ShootWonban #2 - 원반 이동 구현 및 충돌 처리

ChangJin·2024년 8월 7일
0

Unreal Engine5

목록 보기
96/114
post-thumbnail

2024.08.07

이번 글에서는 원반이 포물선을 그리며 날아가는 이동을 구현하고, 총에 맞았을 때 원반이 부서지도록 하는 방법에 대해 다룹니다. 여러 가지 접근 방법을 고려하였으며, 각각의 장단점을 설명하고 최종 구현 방법을 선택한 이유를 자세히 다룹니다.

구현 목표

  • 원반이 포물선을 그리며 날아가는 이동 구현
  • 원반이 총에 맞았을 때 부서지고 부서진 조각들이 자연스럽게 떨어지도록 구현
  • 원반을 랜덤하게 스폰하고 다양한 방향과 속도로 이동시키기

요약

  1. 타임라인을 활용한 포물선 이동 구현

    • 타임라인을 사용하여 원반이 포물선을 그리며 이동하도록 구현했습니다.
    • HandleThrowProgress 함수에서 위치와 회전을 계산하여 원반이 자연스럽게 흔들리도록 설정했습니다.
  2. 충돌 처리 및 부서짐 구현

    • OnCollision 함수를 통해 총알과 충돌 시 원반이 부서지도록 했습니다.
    • 부서진 조각들은 SpawnBrokenPieces 함수를 통해 생성되며, 각 조각은 물리 시뮬레이션이 활성화되어 자연스럽게 떨어집니다.
    • SetLifeSpan을 사용하여 부서진 조각들이 5초 후 자동으로 사라지도록 했습니다.
  3. 원반 랜덤 스폰 및 이동 구현

    • WonbanSpawner 클래스에서 원반을 랜덤한 위치에 스폰하도록 설정했습니다.
    • SpawnWonban 함수에서 원반의 이동 방향과 속도를 다양하게 설정하여 게임의 난이도와 재미를 높였습니다.

1. 원반 이동 구현

이번 게임의 기획에서는 액터가 포물선을 그리면서 이동하는 것을 만들어야 했습니다. 생각했던 방법은 2가지가 있습니다. AddImpulse로 실제 힘을 주어서 날아가게끔 하는 것과, 타임라인을 사용해서 날아가게끔 하는 것입니다. 물리 엔진에 대한 의존성을 줄이고 포물체의 연직방향으로 올라간 최대높이를 조절할 수 있게 만들기 위해서 타임라인을 사용했습니다.

방법 1: 물리 기반 이동

장점: Unreal Engine의 물리 엔진을 활용하여 자연스러운 포물선 운동을 구현할 수 있습니다.
단점: 세부적인 제어가 어려울 수 있으며, 물리 엔진에 대한 의존성이 큽니다.

void AWonban::InitializeThrow()
{
    FVector ImpulseDirection = FVector(1000.0f, 0.0f, 500.0f);
    WonbanMeshComponent->AddImpulse(ImpulseDirection, NAME_None, true);
}
a에서 b 사이의 포물선을 만들기 어렵다

방법 2: 타임라인을 활용한 커스텀 이동

장점: 이동 경로를 정확하게 제어할 수 있으며, 원하는 포물선 형태를 쉽게 구현할 수 있습니다.
단점: 직접 구현해야 하므로 코드가 복잡해질 수 있습니다.

void AWonban::HandleThrowProgress(float Value)
{
    FVector NewLocation = InitialLocation 
                          + (ThrowDirection * ThrowSpeed * Value)  // 직선 이동
                          + (FVector::UpVector * FMath::Sin(Value * PI) * ParabolaHeight);  // 포물선 운동
    SetActorLocation(NewLocation);

    // 원반의 회전 계산 (위아래로 더 빠르게 흔들리게)
    float RotationFrequency = FMath::RandRange(15.0f, 25.0f);  // 회전 주파수 조정
    FRotator NewRotation = FRotator(FMath::Sin(Value * PI * RotationFrequency) * RotationPower, GetActorRotation().Yaw, GetActorRotation().Roll);
    SetActorRotation(NewRotation);
}

2. 원반 충돌 처리 및 부서짐 구현

  • 원반이 총에 맞았을 때 바로 사라지게되면 시각적으로 어색할 수 있어서 여러 조각이 생겨나도록 했습니다.
  • 그리고 부서진 조각들은 부드럽게 떨어지는 효과를 주었습니다.

구현 방법

1. 원반이 총에 맞았을 때 부서진 조각 생성
2. 부서진 조각들이 바닥으로 떨어지도록 물리 시뮬레이션 활성화
3. 부서진 조각들이 일정 시간 후 자동으로 사라지도록 설정

void AWonban::OnCollision(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
    if(OtherActor->IsA<AShootWonBanProjectile>())
    {
        SpawnBrokenPieces();
        Destroy();
    }
}

void AWonban::SpawnBrokenPieces()
{
    for (int i = 0; i < 5; i++)
    {
        FVector SpawnLocation = GetActorLocation();
        FRotator SpawnRotation = FRotator::ZeroRotator;
        AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ABrokenPiece::StaticClass(), SpawnLocation, SpawnRotation);
        if(SpawnedActor)
        {
            ABrokenPiece* BrokenPiece = Cast<ABrokenPiece>(SpawnedActor);
            if (BrokenPiece)
            {
                BrokenPiece->SetLifeSpan(5.0f); // 5초 후 파괴

                UStaticMeshComponent* MeshComponent = Cast<UStaticMeshComponent>(BrokenPiece->GetComponentByClass(UStaticMeshComponent::StaticClass()));
                if (MeshComponent)
                {
                    FVector ImpulseDirection = FVector(FMath::FRandRange(-1.0f, 1.0f), FMath::FRandRange(-1.0f, 1.0f), FMath::FRandRange(0.5f, 1.5f));
                    MeshComponent->AddImpulse(ImpulseDirection * 500.0f);
                }
            }
        }
    }
}

3. 원반 랜덤 스폰 및 이동 구현

  • 원반을 특정 위치에만 스폰하면 게임이 단조로워질 수 있습니다.
  • 원반의 이동 방향과 속도를 다양하게 설정하여 게임의 난이도와 재미를 증가시킬 필요가 있습니다.

구현 방법

1. 원반을 랜덤 위치에 스폰
2. 원반의 이동 방향과 속도를 다양하게 설정

#include "WonbanSpawner.h"
#include "TimerManager.h"
#include "Wonban.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"

// Sets default values
AWonbanSpawner::AWonbanSpawner()
{
    PrimaryActorTick.bCanEverTick = true;
}

// Called when the game starts or when spawned
void AWonbanSpawner::BeginPlay()
{
    Super::BeginPlay();
    GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AWonbanSpawner::SpawnWonban, 3.0f, true);
}

void AWonbanSpawner::SpawnWonban()
{
    FVector SpawnLocation = GetActorLocation() + FVector(20,0,0);
    FRotator SpawnRotation = FRotator::ZeroRotator;
    FActorSpawnParameters SpawnParameters;

    AWonban* SpawnedWonban = GetWorld()->SpawnActor<AWonban>(AWonban::StaticClass(), SpawnLocation, SpawnRotation, SpawnParameters);

    if(SpawnedWonban)
    {
        SpawnedWonban->SetActorScale3D(FVector(0.5f, 0.5f, 0.1f));
        SpawnedWonban->RotationFrequency = FMath::RandRange(15.0f, 25.0f);
        SpawnedWonban->RotationPower = FMath::RandRange(3.0f, 5.0f);
        SpawnedWonban->ParabolaHeight = FMath::RandRange(200.0f, 250.0f);
        SpawnedWonban->ThrowDirection = FVector(FMath::RandRange(0.0f, 1.0f),FMath::RandRange(0.0f, 1.0f),0.0f).GetSafeNormal();
        SpawnedWonban->TargetLocation = SpawnedWonban->ThrowDirection * FMath::RandRange(500.0f, 1000.0f);
        SpawnedWonban->InitializeThrow(ThrowCurve);
    }
}

// Called every frame
void AWonbanSpawner::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

이번 글에서는 원반 이동과 충돌 처리, 부서짐 효과를 구현하는 과정과 그 방법에 대해 상세히 다루었습니다. 또한, 원반을 랜덤하게 스폰하고 다양한 방향으로 이동시키는 방법을 설명했습니다. 다음 작업에서는 게임 사운드와 UI 구성을 진행할 예정입니다. 많은 관심과 피드백 부탁드립니다!

profile
게임 프로그래머

0개의 댓글