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 ASGameMode::RestartPlayer(class AController* NewPlayer) { /* Fallback to PlayerStart picking if team spawning is disabled or we're trying to spawn a bot. */ if (!bSpawnAtTeamPlayer || (NewPlayer->PlayerState && NewPlayer->PlayerState->bIsABot)) { Super::RestartPlayer(NewPlayer); return; } /* Look for a live player to spawn next to */ FVector SpawnOrigin = FVector::ZeroVector; FRotator StartRotation = FRotator::ZeroRotator; for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; It++) { ASCharacter* MyCharacter = Cast<ASCharacter>(*It); if (MyCharacter && MyCharacter->IsAlive()) { /* Get the origin of the first player we can find */ SpawnOrigin = MyCharacter->GetActorLocation(); StartRotation = MyCharacter->GetActorRotation(); break; } } /* No player is alive (yet) - spawn using one of the PlayerStarts */ if (SpawnOrigin == FVector::ZeroVector) { Super::RestartPlayer(NewPlayer); return; } /* Get a point on the nav mesh near the other player */ FVector StartLocation = UNavigationSystem::GetRandomPointInRadius(NewPlayer, SpawnOrigin, 250.0f); // Try to create a pawn to use of the default class for this player if (NewPlayer->GetPawn() == nullptr && GetDefaultPawnClassForController(NewPlayer) != nullptr) { FActorSpawnParameters SpawnInfo; SpawnInfo.Instigator = Instigator; APawn* ResultPawn = GetWorld()->SpawnActor<APawn>(GetDefaultPawnClassForController(NewPlayer), StartLocation, StartRotation, SpawnInfo); if (ResultPawn == nullptr) { UE_LOG(LogGameMode, Warning, TEXT("Couldn't spawn Pawn of type %s at %s"), *GetNameSafe(DefaultPawnClass), &StartLocation); } NewPlayer->SetPawn(ResultPawn); } if (NewPlayer->GetPawn() == nullptr) { NewPlayer->FailedToSpawnPawn(); } else { NewPlayer->Possess(NewPlayer->GetPawn()); // If the Pawn is destroyed as part of possession we have to abort if (NewPlayer->GetPawn() == nullptr) { NewPlayer->FailedToSpawnPawn(); } else { // Set initial control rotation to player start's rotation NewPlayer->ClientSetRotation(NewPlayer->GetPawn()->GetActorRotation(), true); FRotator NewControllerRot = StartRotation; NewControllerRot.Roll = 0.f; NewPlayer->SetControlRotation(NewControllerRot); SetPlayerDefaults(NewPlayer->GetPawn()); } } }