팔의 재장전 애니메이션과 총의 재장전 애니메이션을 R키를 누르면 싱크에 맞게 재생하도록 구현했습니다. Do once 노드 대신에 불리언으로 한번 실행을 구현했는데, 타이머 설정을 통해 장전하는 시간 동안에는 R키 연타로 재장전 애니메이션이 여러번 재생되는 것을 막았습니다.
AVICharacter::Reload()
void AVICharacter::Reload()
{
if (PrimaryWeapon->GetAmmoCount() < PrimaryWeapon->GetMaxAmmo())
{
if (!bDoOnceReload && !bIsReloading)
{
bIsReloading = true;
FirstPersonMesh->GetAnimInstance()->Montage_Play(ReloadActionMontage,1.0f);
PrimaryWeapon->Reload();
FTimerHandle ReloadTimeHandle;
GetWorld()->GetTimerManager().SetTimer(ReloadTimeHandle, FTimerDelegate::CreateLambda([&]()
{
bIsReloading = false;
// TimerHandle 초기화
GetWorld()->GetTimerManager().ClearTimer(ReloadTimeHandle);
}), PrimaryWeapon->GetReloadTime(), false);
bDoOnceReload = false;
}
}
}
Weaponbase 에서도 동시에 몽타주를 재생하고, 재생 후에는 탄약 수를 재조정 했습니다.
AVIWeaponbase::Reload()
void AVIWeaponbase::Reload()
{
Mesh->PlayAnimation(ReloadActionAnimation, false);
FTimerHandle ReloadTimeHandle;
GetWorld()->GetTimerManager().SetTimer(ReloadTimeHandle, FTimerDelegate::CreateLambda([&]()
{
SetAmmoCount(GetMaxAmmo());
// TimerHandle 초기화
GetWorld()->GetTimerManager().ClearTimer(ReloadTimeHandle);
}), ReloadTime, false);
}
같은 방식으로 마우스 좌클릭을 했을 때 팔의 발사 애니메이션이 재생되게 해 주었고, Weaponbase에서는 AmmoCheck() 가 호출됩니다. AmmoCheck에서는 총의 발사 애니메이션이 재생된 뒤 LineTrace() 를 호출해 라인 트레이싱을 실행합니다.
AVIWeaponbase::AmmoCheck()
void AVIWeaponbase::AmmoCheck()
{
AmmoCount--;
//DF("Ammo %d",AmmoCount);
if (UWorld* World = GetWorld())
{
// Get the player controller for the first player (index 0)
APlayerController* PC = UGameplayStatics::GetPlayerController(World, 0);
if (PC)
{
AVICharacter* Character = Cast<AVICharacter>(PC->GetCharacter());
if (!Character->GetbIsReloading())
{
Mesh->PlayAnimation(FireActionAnimation, false);
UE_LOG(LogTemp, Log, TEXT("Fire Animation "));
LineTrace();
}
}
}
}
Lintrace 는 UKismetSystemLibrary 를 통해 호출하였고, 미리 파라미터들을 정한 다음 실행하였습니다. 카메라에서 화면 정중앙으로 trace 하는 것과, 총구(Muzzle)에서 정 중앙으로 라인 트레이싱하는 두 로직 다 실행합니다.
라인 트레이싱의 시작은 각각 시작 위치에서 시작 위치 + 시작위치에서의 정면 직선벡터 * 거리 로 계산했습니다.
AVIWeaponbase::LineTrace()
void AVIWeaponbase::LineTrace()
{
if (UWorld* World = GetWorld())
{
// Get the player controller for the first player (index 0)
APlayerController* PC = UGameplayStatics::GetPlayerController(World, 0);
if (PC)
{
AVICharacter* Character = Cast<AVICharacter>(PC->GetCharacter());
FHitResult HitResult;
FVector TraceStart = Character->GetCamera()->GetComponentLocation();
FVector TraceEnd = Character->GetCamera()->GetForwardVector() * 20000.0f + TraceStart;
/* 탄퍼짐 설정
FVector BulletSpreadRandVector(
FMath::RandRange(BulletSpread * -1.0f, BulletSpread)
, FMath::RandRange(BulletSpread * -1.0f, BulletSpread)
, FMath::RandRange(BulletSpread * -1.0f, BulletSpread)
);
TraceEnd = TraceEnd + BulletSpreadRandVector;
*/
TArray<AActor*> ActorsToIgnore;
FColor ColorBeforeHit = FColor::Red;
FColor ColorAfterHit = FColor::Green;
float ColorsLifeTime = 5.f;
if (UKismetSystemLibrary::LineTraceSingle(
World,
TraceStart,
TraceEnd,
UEngineTypes::ConvertToTraceType(ECC_Visibility),
false,
ActorsToIgnore,
EDrawDebugTrace::ForDuration,
HitResult,
true,
ColorBeforeHit,
ColorAfterHit,
ColorsLifeTime
))
{
FHitResult HitResultMuzzle;
FVector TraceStartMuzzle = Muzzle->GetComponentLocation();
FVector TraceEndMuzzle = HitResult.ImpactPoint;
TArray<AActor*> ActorsToIgnoreMuzzle;
FColor ColorBeforeHitMuzzle = FColor::Green;
FColor ColorAfterHitMuzzle = FColor::Green;
float ColorsLifeTimeMuzzle = 5.f;
UKismetSystemLibrary::LineTraceSingle(
World,
TraceStartMuzzle,
TraceEndMuzzle,
UEngineTypes::ConvertToTraceType(ECC_Visibility),
false,
ActorsToIgnoreMuzzle,
EDrawDebugTrace::ForDuration,
HitResultMuzzle,
true,
ColorBeforeHitMuzzle,
ColorAfterHitMuzzle,
ColorsLifeTimeMuzzle);
}
}
}
}
실행 영상
'언리얼엔진5 > FPS 게임 1인 프로젝트' 카테고리의 다른 글
[UE5 FPS 프로젝트] 6. ADS(조준) 시스템 (0) | 2024.06.18 |
---|---|
[UE5 FPS 프로젝트] 5. 총 추가 구현 및 Swap (0) | 2024.06.17 |
[UE5 FPS 프로젝트] 4. 총알 궤적, 총구 화염, 총알 자국, 탄퍼짐 구현 (0) | 2024.06.14 |
[UE5 FPS 프로젝트] 3. HUD 및 피격 구현 (0) | 2024.06.13 |
[UE5 FPS 프로젝트] 1. 1인칭 구현 및 무기 부착 (0) | 2024.06.12 |