총기의 단발과 연사를 구현하다가 알게 된 내용으로 간단한 내용이지만 다음번에 사용할 때 헷갈리지 않으려고 정리한 글입니다.
1. Triggered
EnhancedInputComponent->BindAction(PlayerController->ShootAction,
ETriggerEvent::Triggered, this, &APlayerCharacter::StartShoot);
- ETriggerEvent를 Triggered 상태로 바인딩을 하게 되면, 우리가 마우스나 키보드를 누르고 있는 동안 계속해서 StartShoot이라는 함수가 call된다.
- 그렇기 때문에 연사를 구현하기 위해서 Started 보다는 Triggered로 바인딩하는 것이 좋다고 생각했다.
- 총이 연사로 발사되더라도, 연사율을 통해서 속도가 변해야 하기 때문에 (그냥 실행하면 속도가 너무 빠름) Timer를 통해서 다음번 call 되는 순간을 정해 주었다.
//auto fire
if (CurrentWeapon->GetAutoFire())
{
GetWorld()->GetTimerManager().SetTimer(FireRateTimerHandle, this, &APlayerCharacter::ResetShoot, CurrentWeapon->GetFireRate(), true);
}
2. Started
EnhancedInputComponent->BindAction(PlayerController->EquipWeapon1Action,
ETriggerEvent::Started, this, &APlayerCharacter::EquipWeapon1);
- started로 바인딩 하게 되면, 해당 입력을 누른 순간 딱 한번만 실행된다.
- 위의 코드는 무기를 장착하고, 해제하는 기능을 구현할 때 바인딩한 함수의 모습이다.
3. Completed
EnhancedInputComponent->BindAction(PlayerController->ShootAction,
ETriggerEvent::Completed, this, &APlayerCharacter::StopShoot);
- completed로 바인딩 하게 되면, 입력이 제대로 끝난 순간 해당 함수가 한번 call된다.
- 참고) Jump나 Sprint 등의 동작(move 나 look과 달리) 은 입력이 들어올 때(Started)와 끝날 때(Completed) 두 경우 모두 함수와 바인딩 해주는 것이 좋다고 하였다.
- 총기 발사에 있어서도 Completed인 경우 StopShoot이 call되도록 구현하였다.
4. 결론
단발과 연사 구현 최종 로직
- 기본적으로
- bCanFire인 경우 총을 쏠 수 있도록 구현
- StartShoot 하는 함수를 Triggered로 바인딩 한다.
- StopShoot 하는 함수도 Completed로 구현한다.
- 다음 로직들
- Shoot함수 안에서 총을 쏜 순간 (Weapon의 Fire 함수 call)이 된 순간 bCanFire라는 변수를 false로 만들어 준다.
- 연사라면,
- 타이머를 통해 ResetShoot 함수 call
- ResetShoot 함수에서 bCanFire를 다시 true로 만들어준다.
- 단발이라면,
- StopShoot 함수에서 bCanFire를 true로 만들어준다.
코드
//생성자
{
...
if (PlayerController->ShootAction)
{
EnhancedInputComponent->BindAction(PlayerController->ShootAction,
ETriggerEvent::Triggered, this, &APlayerCharacter::StartShoot);
EnhancedInputComponent->BindAction(PlayerController->ShootAction,
ETriggerEvent::Completed, this, &APlayerCharacter::StopShoot);
}
}
void APlayerCharacter::Shoot()
{
if (CurrentWeapon)
{
if (CurrentWeapon->GetCurrentAmmo() <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Black, FString::Printf(TEXT("you need to reload!")));
return;
}
if (bCanFire)
{
//Real shooting
CurrentWeapon->Fire();
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Black, FString::Printf(TEXT("shoot %d"), CurrentWeapon->GetCurrentAmmo()));
bCanFire = false;
//auto fire
if (CurrentWeapon->GetAutoFire())
{
GetWorld()->GetTimerManager().SetTimer(FireRateTimerHandle, this, &APlayerCharacter::ResetShoot, CurrentWeapon->GetFireRate(), true);
}
}
}
}
void APlayerCharacter::ResetShoot()
{
bCanFire = true;
}
void APlayerCharacter::StartShoot(const FInputActionValue& value)
{
if (bCanFire)
{
Shoot();
}
}
void APlayerCharacter::StopShoot(const FInputActionValue& value)
{
if(CurrentWeapon && !CurrentWeapon->GetAutoFire())
{
bCanFire = true;
}
}
'Unreal Engine' 카테고리의 다른 글
UE5 Issues : 인벤토리 UI (0) | 2025.02.26 |
---|---|
UE5 Issues : 캐릭터 아이템 획득 로직 구현 (0) | 2025.02.24 |
UE5 Issues : 애니메이션 (Motion Matching, Blend Pose) (0) | 2025.02.21 |
UE5 Issues : 이모저모 (0) | 2025.02.13 |
Unreal Engine - 3D UI (0) | 2025.02.13 |