너무 하는게 많고 길었던 FireWeapon 함수에서 Ray Trace 를 통해 끝점을 구하는 부분을 따로 함수로 빼서 FireWeapon 함수를 간략하게 정리했다.
bool AShooterCharacter::GetBeamEndLocation(const FVector& MuzzleSocketLocation, FVector& OutBeamLocation)
{
// Get Current size of the view port
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
//Get Screen space of crosshairs
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
CrosshairLocation.Y -= 50.0f;
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
//Get World position and direction of crosshairs
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(this, 0)
, CrosshairLocation
, CrosshairWorldPosition
, CrosshairWorldDirection);
// was deprojection successful?
if (bScreenToWorld)
{
FHitResult ScreenTraceHit;
const FVector Start{ CrosshairWorldPosition };
const FVector End{ CrosshairWorldPosition + CrosshairWorldDirection * 50'000.f };
// Set beam end point to line trace end point
OutBeamLocation = End;
// Trace outward from crosshairs world location
GetWorld()->LineTraceSingleByChannel(ScreenTraceHit
, Start
, End
, ECollisionChannel::ECC_Visibility);
// was ther a tarce hit?
if (ScreenTraceHit.bBlockingHit)
{
// Beam end point is now trace hit location
OutBeamLocation = ScreenTraceHit.Location;
}
// Perform a second trace , this tim from the gun barrel
FHitResult WeaponTraceHit;
const FVector WeaponTraceStart{ MuzzleSocketLocation };
const FVector WeaponTraceEnd{ OutBeamLocation };
GetWorld()->LineTraceSingleByChannel(WeaponTraceHit
, WeaponTraceStart
, WeaponTraceEnd
, ECollisionChannel::ECC_Visibility);
// Object between barrel and BeamEndPoint?
if (WeaponTraceHit.bBlockingHit)
OutBeamLocation = WeaponTraceHit.Location;
return true;
}
return false;
}
void AShooterCharacter::FireWeapon()
{
UE_LOG(LogTemp, Warning, TEXT("Fire Weapon."));
if (FireSound)
{
UGameplayStatics::PlaySound2D(this, FireSound);
}
const USkeletalMeshSocket* BarrelSocket = GetMesh()->GetSocketByName("Barrel");
if (BarrelSocket)
{
const FTransform SocketTransform = BarrelSocket->GetSocketTransform(GetMesh());
if (MuzzleFlash)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleFlash, SocketTransform);
}
// Get Current size of the view port
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
//Get Screen space of crosshairs
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
CrosshairLocation.Y -= 50.0f;
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
//Get World position and direction of crosshairs
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(this, 0)
, CrosshairLocation
, CrosshairWorldPosition
, CrosshairWorldDirection);
// was deprojection successful?
if (bScreenToWorld)
{
FHitResult ScreenTraceHit;
const FVector Start{ CrosshairWorldPosition };
const FVector End{ CrosshairWorldPosition + CrosshairWorldDirection * 50'000.f };
// Set beam end point to line trace end point
FVector BeamEndPoint{ End };
// Trace outward from crosshairs world location
GetWorld()->LineTraceSingleByChannel(ScreenTraceHit
, Start
, End
, ECollisionChannel::ECC_Visibility);
// was ther a tarce hit?
if (ScreenTraceHit.bBlockingHit)
{
// Beam end point is now trace hit location
BeamEndPoint = ScreenTraceHit.Location;
}
// Perform a second trace , this tim from the gun barrel
FHitResult WeaponTraceHit;
const FVector WeaponTraceStart{ SocketTransform.GetLocation() };
const FVector WeaponTraceEnd{ BeamEndPoint };
GetWorld()->LineTraceSingleByChannel(WeaponTraceHit
, WeaponTraceStart
, WeaponTraceEnd
, ECollisionChannel::ECC_Visibility);
// Object between barrel and BeamEndPoint?
if (WeaponTraceHit.bBlockingHit)
BeamEndPoint = WeaponTraceHit.Location;
// Spawn impact particles after updating Beampoint
if (ImpactParticles)
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactParticles, WeaponTraceHit.Location);
if (BeamParticles)
{
UParticleSystemComponent* Beam = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), BeamParticles, SocketTransform);
if (Beam)
Beam->SetVectorParameter(FName("Target"), BeamEndPoint);
}
}
}
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && HipFireMontage)
{
AnimInstance->Montage_Play(HipFireMontage);
AnimInstance->Montage_JumpToSection(FName("StartFire"));
}
}
void AShooterCharacter::FireWeapon()
{
UE_LOG(LogTemp, Warning, TEXT("Fire Weapon."));
if (FireSound)
UGameplayStatics::PlaySound2D(this, FireSound);
const USkeletalMeshSocket* BarrelSocket = GetMesh()->GetSocketByName("Barrel");
if (BarrelSocket)
{
const FTransform SocketTransform = BarrelSocket->GetSocketTransform(GetMesh());
if (MuzzleFlash)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleFlash, SocketTransform);
}
FVector BeamEnd;
bool bBeamEnd = GetBeamEndLocation(SocketTransform.GetLocation(), BeamEnd);
if (bBeamEnd)
{
if (ImpactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactParticles, BeamEnd);
}
UParticleSystemComponent* Beam = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), BeamParticles, SocketTransform);
if (Beam)
{
Beam->SetVectorParameter(FName("Target"), BeamEnd);
}
}
}
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && HipFireMontage)
{
AnimInstance->Montage_Play(HipFireMontage);
AnimInstance->Montage_JumpToSection(FName("StartFire"));
}
}