이전 포스트에서 발사체를 구현하고 에임 사이즈에 따라서 탄이 튀는 것 까지 구현을 하였다.
이번 시간에는 발사시 발생하는 반동과 재장전 로직에 대해서 다루겠다.
1.Camera Shake를 사용한 반동 구현
ULegacyCameraShake 클래스를 상속받는 UiCameraShake클래스를 생성해준다.
UiCameraShake.h
#pragma once
#include "CoreMinimal.h"
#include "Shakes/LegacyCameraShake.h"
#include "UiCameraShake.generated.h"
UCLASS()
class PROJECT_4_API UUiCameraShake : public ULegacyCameraShake
{
GENERATED_BODY()
public:
UUiCameraShake();
};
UiCameraShake.cpp
#include "Player/Ui/UiCameraShake.h"
UUiCameraShake::UUiCameraShake() {
// 카메라 쉐이크 설정
OscillationDuration = 0.1f;
OscillationBlendInTime = 0.05f;
OscillationBlendOutTime = 0.05f;
RotOscillation.Pitch.Amplitude = 1.0f;
RotOscillation.Pitch.Frequency = 25.0f;
RotOscillation.Yaw.Amplitude = 1.0f;
RotOscillation.Yaw.Frequency = 25.0f;
}
생성자에서 초기화하는 변수들은 다음과 같다.
설정값 | 설명 | 값 | 효과 |
---|---|---|---|
OscillationDuration | 카메라 쉐이크가 지속되는 총 시간 (초 단위). | 0.1f |
0.1초 동안 진동이 발생합니다. |
OscillationBlendInTime | 쉐이크가 서서히 시작되는 시간 (초 단위). | 0.05f |
0.05초 동안 진동이 부드럽게 증가합니다. |
OscillationBlendOutTime | 쉐이크가 서서히 종료되는 시간 (초 단위). | 0.05f |
0.05초 동안 진동이 부드럽게 감소합니다. |
RotOscillation.Pitch.Amplitude | 피치(Pitch) 축의 회전 진폭 (위아래 흔들림의 정도). | 1.0f |
카메라가 위아래로 약간 흔들립니다. |
RotOscillation.Pitch.Frequency | 피치(Pitch) 축의 진동 빈도 (초당 진동 횟수). | 25.0f |
카메라가 초당 25번 위아래로 진동합니다. |
RotOscillation.Yaw.Amplitude | 요(Yaw) 축의 회전 진폭 (좌우 흔들림의 정도). | 1.0f |
카메라가 좌우로 약간 흔들립니다. |
RotOscillation.Yaw.Frequency | 요(Yaw) 축의 진동 빈도 (초당 진동 횟수). | 25.0f |
카메라가 초당 25번 좌우로 진동합니다. |
void UWeaponComponent::ApplyCameraShake() const
{
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
if (PlayerController)
{
PlayerController->ClientStartCameraShake(UUiCameraShake::StaticClass(), WeaponData->Recoil);
}
}
WeaponComponent에서 발사할때마다 해당 함수를 호출하여 카메라에 진동을 발생시킬 수 있다.
여기서 매개변수로 전달되는 Recoil 값은 스케일값이며 UiCameraShake에서 초기화한 값 * Recoil 으로 반동 세기를 조절해줄 수 있으며 따라서 0일때에는 반동이 사라진다.
2. 연사 시스템 구현
일반적인 FPS 게임처럼 마우스 우클릭을 꾹 누르면 총알이 연속적으로 발사되도록 구현해보자.
우선, 이전에 작성한 WeaponComponent에 현재 발사 중인지 여부를 확인할 수 있는 플래그 IsShooting과, 일정 시간마다 함수를 반복 호출할 TimerHandle을 선언한다. 또한, 마지막 발사 시간을 기록할 LastFireTime 변수도 함께 추가한다.
private:
FTimerHandle ShootingTimerHandle;
bool IsShooting;
float LastFireTime
이제 기존에 총알을 발사하던 함수를 살짝 수정해서 FireWeapon과 StopFireWeapon으로 나눈뒤 Shoot이라는 함수에서 총알이 발사되도록 한다.
private:
void Shoot();
public:
UFUNCTION(BlueprintCallable, Category = "Weapon")
void FireWeapon();
UFUNCTION(BlueprintCallable, Category = "Weapon")
void StopFireWeapon();
기존의 총알을 발사하는 함수인 FireWeapon 함수가 호출되면, IsShooting을 true로 설정한 다음 Shoot 함수가 호출되어 총알이 발사 조건에 맞을 때만 한 발 발사되도록 한다. 그 다음 TimerManager를 통해 Shoot 함수를 일정 간격으로 호출하도록 스케줄러를 등록한다.
void UWeaponComponent::FireWeapon()
{
IsShooting = true;
float CurrentTime = GetWorld()->GetTimeSeconds();
// 발사 간격 확인
if (CurrentTime - LastFireTime > 1.0f / WeaponData->FireRate)
{
Shoot();
}
GetWorld()->GetTimerManager().SetTimer(
ShootingTimerHandle, this, &UWeaponComponent::Shoot, 1.0f / WeaponData->FireRate, true
); // 연사 타이머 설정
}
발사가 끝나면(플레이어가 좌클릭 버튼을 떼면) StopFireWeapon 함수가 호출된다. 이 함수는 IsShooting을 false로 설정하고, 등록된 Shoot 함수 스케줄러를 삭제하여 타이머를 중지한다.
void UWeaponComponent::StopFireWeapon()
{
IsShooting = false;
GetWorld()->GetTimerManager().ClearTimer(ShootingTimerHandle); // 타이머 중지
}
Shoot 함수는 기존 FireWeapon을 그대로 복사하되 맨 앞에 IsShooting이 false일때 return되는 구문과 발사가 완료되면 마지막 발사시간을 갱신해주는 코드를 추가하면 된다.
void UWeaponComponent::Shoot(){
if (CurrentAmmoCount == 0 || !SkeletalMeshComponent || !UiComponent || !IsShooting) return;
// ... 기존 코드
LastFireTime = GetWorld()->GetTimeSeconds();// 마지막 발사시간 갱신
}

'Unreal 5 > FPS Shooting' 카테고리의 다른 글
5. [Unreal 5 / C++] 발사체와 오브젝트 풀링 (0) | 2025.01.08 |
---|---|
3. [Unreal 5 / C++] 동적 크로스헤어 구현 (1) | 2025.01.03 |
2. [Unreal 5 / C++] 발사체 구현 하기 (1) | 2025.01.02 |
1. [Unreal 5 / C++] 슈팅 구현 하기 (0) | 2024.12.31 |