I’ve seen previous DevForum posts here asking questions on changing the voice chat range, however, all of them really have no responses. I am wondering how I could change the range of voice chat and also disable the ability to hear voice chat through walls and smooth terrain. I heard some suggestions about using RollOffMaxDistance - but this does not work.
Sorry to bump this post but I wanted to answer it incase anyone else wants to know.
If you are using the Audio API then all audio from the mic will have to wired up to an audio emitter which you would place inside the player character. You can then use the SetDistanceAttenuation() method to adjust the range of the emitter:
For example:
local emitter = script.Parent:FindFirstChild("VoiceEmitter")
if not emitter then return end
local MIN_DISTANCE = 7
local MAX_DISTANCE = 150
local CURVE_STEP_SIZE = 2
local voiceCurve = {}
for i = MIN_DISTANCE, MAX_DISTANCE, CURVE_STEP_SIZE do
voiceCurve[i] = ((i - MIN_DISTANCE) - (MAX_DISTANCE - MIN_DISTANCE))^2 / (MAX_DISTANCE - MIN_DISTANCE)^2
end
voiceCurve[MAX_DISTANCE] = 0
emitter:SetDistanceAttenuation(voiceCurve)
SetDistanceAttenuation takes a table which coresponds to what the volume of the audio emitter should from a given number of studs. You can read about it in AudioEmitter | Documentation - Roblox Creator Hub.
As for disabling voice chat through walls, you can achieve this by raycasting from each player to the camera and checking if a part is detected. I have done something similar before but with audio emitters inside the workspace:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local cachedParts = {} -- Array to store parts with MuffledEffects folder
-- Function to check if a part has a MuffledEffects folder and an AudioEmitter
local function cacheMuffledParts()
cachedParts = {} -- Reset the cached parts list
for _, part in workspace:GetDescendants() do
if part:IsA("BasePart") then
local muffleFolder = part:FindFirstChild("MuffledEffects")
local emitter = part:FindFirstChildWhichIsA("AudioEmitter")
if muffleFolder and emitter then
table.insert(cachedParts, part) -- Add to cached array
end
end
end
end
-- Call this function once at the start to cache the parts
cacheMuffledParts()
-- Occlusion check with debug prints
local function isOccluded(emitterPos, playerPos, ignoreList)
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = ignoreList
rayParams.FilterType = Enum.RaycastFilterType.Exclude
-- Raycasting from emitter position to player position
local direction = playerPos - emitterPos
local result = workspace:Raycast(emitterPos, direction, rayParams)
if result then
return true -- Something was hit
else
return false -- Nothing was hit
end
end
-- Continuously check the cached parts
RunService.Heartbeat:Connect(function()
local char = player.Character
if not char then return end
local head = char:FindFirstChild("Head")
if not head then return end
local playerPos = head.Position
-- Loop through cached parts only
for _, part in ipairs(cachedParts) do
local muffleFolder = part:FindFirstChild("MuffledEffects")
local emitter = part:FindFirstChildWhichIsA("AudioEmitter")
if muffleFolder and emitter then
-- Check if there's an obstruction in the raycast
local blocked = isOccluded(part.Position, playerPos, {char})
-- Set the bypass to false if blocked, true if not blocked
for _, effect in ipairs(muffleFolder:GetChildren()) do
effect.Bypass = not blocked -- If blocked, Bypass = false, otherwise Bypass = true
end
end
end
end)
-- Listen for new parts added to the workspace with MuffledEffects
workspace.DescendantAdded:Connect(function(descendant)
if descendant:IsA("BasePart") then
local muffleFolder = descendant:FindFirstChild("MuffledEffects")
local emitter = descendant:FindFirstChildWhichIsA("AudioEmitter")
if muffleFolder and emitter then
table.insert(cachedParts, descendant) -- Add to cached array
end
end
end)
-- Listen for parts being removed from the workspace
workspace.DescendantRemoving:Connect(function(descendant)
if descendant:IsA("BasePart") then
local index = table.find(cachedParts, descendant)
if index then
table.remove(cachedParts, index) -- Remove from cached array
end
end
end)
This script checks to see if a part in the workspace has a specific folder called MuffledEffects and disables or enables the bypass on any audio filters based on the ray to create a “muffled” version. One issue with this however is that even a small box in the way of the player with trigger the muffle so using multiple rays at different parts of the player or by filtering out small parts using tags/ groups could make this system feel more realistic.
Hope this helped someone.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.