I wrote a script a while back that is ultimately flawed in peformance… Due to multiple loops being inside of each other running every frame, while looping through the entire workspace. The game is unplayble.
I have attempted some ideas. For example only looping through the players by using a folder inside workspace to store players, however local parts = workspace:GetPartBoundsInBox(boxPos, boxSize) can only use workspace apparently. Which does confuse me a bit since this almost never seems like a viable function for any game peformance wise.
All of these ideas however, either don’t work as shown above, or even if I manage to get them to work, they won’t be enough to get the loop to run at a reasonable peformance.
My question is then how I should approach this? Do you see any peformance improvements that can be done to the current loop? I could write a new script that thinks about peformance, but without suggestions to solve issues like not being able to loop through a folder with GetPartBoundsInBox, it would probably be futile.
game:GetService("RunService").RenderStepped:Connect(function()
for i, zone in pairs (soundZones) do
local boxPos = zone.CFrame
local boxSize = zone.Size
local parts = workspace:GetPartBoundsInBox(boxPos, boxSize)
for i, part in pairs (parts) do
if part.Parent.Name == player.Name then
found = true
break
else
found = false
end
end
if found then
local sound = sounds:FindFirstChild(zone.Name)
if sound and sound.IsPlaying == false then
local check = sounds:GetChildren()
for i,v in pairs(check) do
v:Stop()
end
sound:Play()
latestZone = zone.Name
if game.Lighting.ClockTime == 15 then
zoneText.Text = string.gsub(zone.Name, "Day", "")
elseif game.Lighting.ClockTime == 3 then
zoneText.Text = string.gsub(zone.Name, "Night", "")
end
zoneText.Position = UDim2.new(0,0,0.00,0)
wait(0.1)
zoneText.TextTransparency = 0
zoneText:TweenPosition(UDim2.new(0,0,0.12,0))
wait(2.5)
while zoneText.TextTransparency < 1 do
task.wait(0.05)
zoneText.TextTransparency += 0.03
end
end
else
--code to give music when player joins in deadzone
end
end
end)
how would looping through the players service be sat up here? It seems to me that local parts = workspace:GetPartBoundsInBox(boxPos, boxSize) is nessecary to detect anything at all
what are the capabilities of the function “Touched”
can it detect if a player teleports inside and other funky things needed in gameplay?
if so, it’s true that it would improve peformance a lot. Although the RenderStepped loop will still have to be turned into a function and ran when clocktime changes, since day/night has different music… but ~60x less laggy I suppose.
Yep, as far as I know that’s how it should work. Any collision between them (whether that’s through teleportation, walking into it, etc.) should fire the Touched event. Whenever they leave that (same thing, teleportation, walking out, etc) should fire TouchEnded
hey again, I wrote a script that mostly works…
There is a bug which I think is caused by the humanoidrootpart not being local somehow? The “ran” (zoneDetected function) prints at random times (other than printing when a player moves to a zone), sometimes many times and sometimes 0 times, and it’s causing everything to be very buggy. The original method didn’t have this issue. I figured it would be local to each player, but apparently not? .Touched is a server event? What should I do to fix this issue.
function zoneDetected(zone)
print("ran")
--check the time of day
if game.Lighting.ClockTime == 15 then
zoneText.Text = string.gsub(zone.Name, "Day", "")
elseif game.Lighting.ClockTime == 3 then
zoneText.Text = string.gsub(zone.Name, "Night", "")
end
--check player's latestZone
if latestZone ~= zone.Name then
--stop and play music
local sound = sounds:FindFirstChild(zone.Name)
if sound and sound.IsPlaying == false then
local check = sounds:GetChildren()
for i,v in pairs(check) do
v:Stop()
end
sound:Play()
end
--set latestZone
print("statementRan")
latestZone = zone.Name
print(latestZone)
--position and tween the zoneUI
zoneText.Position = UDim2.new(0,0,0.00,0)
zoneText.TextTransparency = 0
zoneText:TweenPosition(UDim2.new(0,0,0.12,0))
wait(2.5)
while zoneText.TextTransparency < 1 do
task.wait(0.05)
zoneText.TextTransparency += 0.03
end
end
end
for index,zone in pairs(soundZones) do
zone.Touched:Connect(function(hit)
if hit.Name == "HumanoidRootPart" then
zoneDetected(zone)
end
end)
end
edit: added if hit.Name == "HumanoidRootPart" and hit.Parent.Parent == game.Workspace.playerFolder then and I think it prevents other humanoids from interacting. Which hopefully removes the random function triggers (it’s not that easy to replicate so can’t say for sure it’s fixed), but the players still trigger each other’s music.
edit2: welllll I didn’t think this would actually work, but it does if hit.Name == "HumanoidRootPart" and hit.Parent.Parent == game.Workspace.playerFolder and hit.Parent.Name == player.Name then. Hopefully no more bugs, so I’m gonna tag your message as solved. If you have any more suggestions for this script, go ahead.
You’re doing a lot of calculations every frame. I assume you’re trying to check if the player is in range of a sound? Instead of going from sounds towards checking the players, you should go from players towards checking the sounds.
It’s checking if a player’s character is in a part (“zone”) with a name equal to a sound in soundService. .Touched works with minimal peformance fortunately. No large table looping.
I don’t know what you mean by “from players towards checking the sounds”, but the new .Touched version of the script does the same thing as the old, but without having to loop through a massive table (workspace), because you can physically detect it by touch event instead of that workspace:GetPartBoundsInBox function. And of course the new one minimizes the amount of loops needed (I tested it with 50+ parts in zones and it didn’t cause an issue in peformance window).
local function isPositionInsideZone(position, zoneMin, zoneMax)
return position.x >= zoneMin.x and position.y >= zoneMin.y and position.z >= zoneMin.z and
position.x <= zoneMax.x and position.y <= zoneMax.y and position.z <= zoneMax.z
end
does this function do the same as workspace:GetPartBoundsInBox(this obviously only checking player characters ofc), but without the lag? I just figured out blacklisting is a thing for workspace:GetPartBoundsInBox that makes sure not to loop through the whole workspace(?), which if true, would explain why I had trouble understanding the usage of it. Your version still seems better overall though.