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 ASWeaponInstant::SpawnTrailEffects(const FVector& EndPoint) { // Keep local count for effects BulletsShotCount++; const FVector Origin = GetMuzzleLocation(); FVector ShootDir = EndPoint - Origin; // Only spawn if a minimum distance is satisfied. if (ShootDir.Size() < MinimumProjectileSpawnDistance) { return; } if (BulletsShotCount % TracerRoundInterval == 0) { if (TracerFX) { ShootDir.Normalize(); UGameplayStatics::SpawnEmitterAtLocation(this, TracerFX, Origin, ShootDir.Rotation()); } } else { // Only create trails FX by other players. ASCharacter* OwningPawn = GetPawnOwner(); if (OwningPawn && OwningPawn->IsLocallyControlled()) { return; } if (TrailFX) { UParticleSystemComponent* TrailPSC = UGameplayStatics::SpawnEmitterAtLocation(this, TrailFX, Origin); if (TrailPSC) { TrailPSC->SetVectorParameter(TrailTargetParam, EndPoint); } } } }