How do I make a simple "Terror Radius" for a character?

How do I make a simple system where if you are within (for example) 45 studs from a character, the current sound playing in the workspace pauses and another one from the workspace plays, and if you get out of the range (45 studs) the sound that was paused continues. No layers or anything just walk within, current music stops, music plays, walk out, music stops, past music plays.

You could probably just use a script that stores the positions/size (radius) of the sounds and the sound that would be played.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local UPDATE_TIME = 0.25 -- Seconds between updating the sound

local sounds = { -- Store all your sounds here, as many as you want!
	{Position = Vector3.new(1, 2, 3), Radius = 5, Sound = <SoundInstance>}
}

player.CharacterAdded:Connect(function(character: Model)
	local humanoidRootPart  = character:WaitForChild("HumanoidRootPart")
	local position = humanoidRootPart.Position
	
	while humanoidRootPart do -- Loop until the character respawns
		for _, soundData in sounds do -- Check all sounds
			local sound = soundData.Sound
			local soundPos = soundData.Position
			local soundRadius = soundData.Radius
			
			local distanceToPlayer = (position - soundPos).Magnitude -- Distance to center of sound
			
			if distanceToPlayer < soundRadius then
				if sound:IsPaused() then
					sound:Resume() -- The sound is paused so resume it
				elseif sound:IsPlaying() == false then
					sound:Play() -- The sound hasn't been started yet
				end
			else
				sound:Pause() -- Pause the sound from playing
			end
		end

		task.wait(UPDATE_TIME)
	end
end)

Local Script

This script doesn’t stop the sounds when the player leaves the area so the music would continue where it left off but if you don’t want that you can remove the :Resume/:Pause and just use :Stop/:Play

1 Like

I would store the current playing sound in a variable to avoid playing the same sound multiple times. There’s 2 approaches:

  1. Using some kind of RenderStepped function to calculate the distance between the character’s humanoidrootpart and the player’s using Magnitude. Check if you’re playing the correct audio. If you’re not, stop the other one and play the new one.

  2. Using a spheric part attached to the humanoidRootPart along with .Touched and .TouchEnded events. Here I would have a table containing parts touching for every player. When the .Touched event fires from a player, add that part to the table and check if it was the first part to be added. If it was, stop the other audio and play the new one. When the .TouchEnded event fires from a player, check if that part was in the table, and if it was, remove it and check if it was the last one remaining. If it was, stop the previous audio and play the new one.

I’ll code the approach #1 since I’d say it’s easier
(LocalScript in StarterCharacterScripts)

local CLOSE_SOUND = game.Workspace:WaitForChild("CloseSound")
local FAR_SOUND = game.Workspace:WaitForChild("FarSound")
local DISTANCE_THRESHOLD = 45
local PART = game.Workspace:WaitForChild("TestingPart") -- You should set this to the character's HumanoidRootPart

local hrp = script.Parent:WaitForChild("HumanoidRootPart")
local current_playing_sound

game:GetService("RunService").RenderStepped:Connect(function()
	local distance = (PART.Position - hrp.Position).Magnitude
	if distance <= DISTANCE_THRESHOLD then
		if current_playing_sound ~= CLOSE_SOUND then
			FAR_SOUND:Pause()
			CLOSE_SOUND:Resume()
			current_playing_sound = CLOSE_SOUND
		end
	else
		if current_playing_sound ~= FAR_SOUND then
			CLOSE_SOUND:Pause()
			FAR_SOUND:Resume()
			current_playing_sound = FAR_SOUND
		end
	end
end)
2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.