void ASWeaponInstant::FireWeapon() { const FVector AimDir = GetAdjustedAim(); const FVector CameraPos = GetCameraDamageStartLocation(AimDir); const FVector EndPos = CameraPos + (AimDir * WeaponRange); /* Check for impact by tracing from the camera position */ FHitResult Impact = WeaponTrace(CameraPos, EndPos); const FVector MuzzleOrigin = GetMuzzleLocation(); FVector AdjustedAimDir = AimDir; if (Impact.bBlockingHit) { /* Adjust the shoot direction to hit at the crosshair. */ AdjustedAimDir = (Impact.ImpactPoint - MuzzleOrigin).GetSafeNormal(); /* Re-trace with the new aim direction coming out of the weapon muzzle */ Impact = WeaponTrace(MuzzleOrigin, MuzzleOrigin + (AdjustedAimDir * WeaponRange)); } else { /* Use the maximum distance as the adjust direction */ Impact.ImpactPoint = FVector_NetQuantize(EndPos); } ProcessInstantHit(Impact, MuzzleOrigin, AdjustedAimDir); }
void ASWeaponInstant::FireWeapon() { const FVector AimDir = GetAdjustedAim(); const FVector StartPos = GetCameraDamageStartLocation(AimDir); const FVector EndPos = StartPos + (AimDir * WeaponRange); const FHitResult Impact = WeaponTrace(StartPos, EndPos); ProcessInstantHit(Impact, StartPos, AimDir); }
void ASWeaponInstant::SimulateInstantHit(const FVector& Origin) { const FVector StartTrace = Origin; const FVector AimDir = GetAdjustedAim(); const FVector EndTrace = StartTrace + (AimDir * WeaponRange); const FHitResult Impact = WeaponTrace(StartTrace, EndTrace); if (Impact.bBlockingHit) { SpawnImpactEffects(Impact); SpawnTrailEffects(Impact.ImpactPoint); } else { SpawnTrailEffects(EndTrace); } // Do not spawn near-hit if we actually hit a pawn if (Impact.GetActor() && Impact.GetActor()->IsA(ASCharacter::StaticClass())) { return; } for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; It++) { // Find a locally controlled pawn that is not the instigator of the hit. ASCharacter* OtherPawn = Cast<ASCharacter>(*It); if (OtherPawn && OtherPawn != GetPawnOwner() && OtherPawn->IsLocallyControlled()) { // Calculate shortest distance to point. (using the estimated eye height) const float DistanceToPawn = FVector::CrossProduct(AimDir, OtherPawn->GetActorLocation() - Origin).Size(); /* Owner can be lost before client gets to simulate the hit. */ ASCharacter* P = GetPawnOwner(); if (P) { FVector LookAt = (OtherPawn->GetActorLocation() - GetPawnOwner()->GetActorLocation()); LookAt.Normalize(); float LookDot = FVector::DotProduct(AimDir, LookAt); if (DistanceToPawn < NearHitMaxDistance && LookDot > 0) { // TODO: Play at nearest "almost" hit location. const FVector SoundLocation = Origin + (AimDir * DistanceToPawn); // Volume is based on distance to missed shot float Volume = FMath::Clamp(1 - (DistanceToPawn / NearHitMaxDistance), 0.1f, 1.0f); UGameplayStatics::PlaySoundAtLocation(this, NearHitSound, /*SoundLocation*/ OtherPawn->GetActorLocation(), Volume); } } } } }
void AAmethystWeapon_Projectile::FireWeapon() { FVector ShootDir = GetAdjustedAim(); FVector Origin = GetMuzzleLocation(); // trace from camera to check what's under crosshair const float ProjectileAdjustRange = 10000.0f; const FVector StartTrace = GetCameraDamageStartLocation(ShootDir); const FVector EndTrace = StartTrace + ShootDir * ProjectileAdjustRange; FHitResult Impact = WeaponTrace(StartTrace, EndTrace); // and adjust directions to hit that actor if (Impact.bBlockingHit) { const FVector AdjustedDir = (Impact.ImpactPoint - Origin).SafeNormal(); bool bWeaponPenetration = false; const float DirectionDot = FVector::DotProduct(AdjustedDir, ShootDir); if (DirectionDot < 0.0f) { // shooting backwards = weapon is penetrating bWeaponPenetration = true; } else if (DirectionDot < 0.5f) { // check for weapon penetration if angle difference is big enough // raycast along weapon mesh to check if there's blocking hit FVector MuzzleStartTrace = Origin - GetMuzzleDirection() * 150.0f; FVector MuzzleEndTrace = Origin; FHitResult MuzzleImpact = WeaponTrace(MuzzleStartTrace, MuzzleEndTrace); if (MuzzleImpact.bBlockingHit) { bWeaponPenetration = true; } } if (bWeaponPenetration) { // spawn at crosshair position Origin = Impact.ImpactPoint - ShootDir * 10.0f; } else { // adjust direction to hit ShootDir = AdjustedDir; } } ServerFireProjectile(Origin, ShootDir); }
void AShooterWeapon_Instant::FireWeapon() { const int32 RandomSeed = FMath::Rand(); FRandomStream WeaponRandomStream(RandomSeed); const float CurrentSpread = GetCurrentSpread(); const float ConeHalfAngle = FMath::DegreesToRadians(CurrentSpread * 0.5f); const FVector AimDir = GetAdjustedAim(); const FVector StartTrace = GetCameraDamageStartLocation(AimDir); const FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, ConeHalfAngle, ConeHalfAngle); const FVector EndTrace = StartTrace + ShootDir * InstantConfig.WeaponRange; const FHitResult Impact = WeaponTrace(StartTrace, EndTrace); ProcessInstantHit(Impact, StartTrace, ShootDir, RandomSeed, CurrentSpread); CurrentFiringSpread = FMath::Min(InstantConfig.FiringSpreadMax, CurrentFiringSpread + InstantConfig.FiringSpreadIncrement); }
void AShooterWeapon_Instant::SimulateInstantHit(const FVector& ShotOrigin, int32 RandomSeed, float ReticleSpread) { FRandomStream WeaponRandomStream(RandomSeed); const float ConeHalfAngle = FMath::DegreesToRadians(ReticleSpread * 0.5f); const FVector StartTrace = ShotOrigin; const FVector AimDir = GetAdjustedAim(); const FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, ConeHalfAngle, ConeHalfAngle); const FVector EndTrace = StartTrace + ShootDir * InstantConfig.WeaponRange; FHitResult Impact = WeaponTrace(StartTrace, EndTrace); if (Impact.bBlockingHit) { SpawnImpactEffects(Impact); SpawnTrailEffect(Impact.ImpactPoint); } else { SpawnTrailEffect(EndTrace); } }