Hey Roblox devs. I wanted to ask, is there any way to make while loops faster? Currently, my code is under a while loop with a standard wait() with no values in it (I’m pretty sure the default value is 0.03) but, my while loop is under a tool.equipped:connect(function() and I noticed that this makes the while loop go slower. Now, I THINK it’s going through the while loop every 0.15 seconds and that is not fast enough for what I’m doing within the while loop.
the while loop is not checking through the script fast enough so there is a delay and it’s very noticable in game. If you have any solutions for this, please let me know.
It’s better to avoid while loops when you can do something more efficient, like an event. When using a while loop under an event, a new loop will be created every time the event runs, which can result in performance drops.
Can you show me your code and tell me what your goal is. A while loop may not be the best choice.
tool.Equipped:Connect(function()
equippedStatus = true
local Muzzle = player.Character.Blackout.Preview.MuzzleEffect
while equippedStatus == true do
wait(0.025)
Muzzle.Texture = "rbxassetid://421803006"
wait(0.05)
Muzzle.Texture = "rbxassetid://421803091"
wait(0.025)
Muzzle.Texture = "rbxassetid://421803134"
if player.Character.Blackout.ShootingStatus.Value == true then
MuzzleEvent:FireServer()
end
if player.Character.Blackout.ShootingStatus.Value == false then
MuzzleStopEvent:FireServer()
end
wait()
end
end)
my goal with this is to detect when a player is shooting a gun, and control the muzzle’s (a particle emitter) visibility. I can show you the server script the recieves the remote event if needed.
I have a while loop below this code that controls the “equipped status” variable, so don’t worry about that.
Obviously it’s looping the “fire server” command, which it’s supposed to but I want it to go faster. If a player lightly taps their mouse button 1 (firing button), the muzzle doesn’t show because of the delay.
it does work. equipped status is just used to control the while loop. Again, my only problem is the delay since the while loop is repeating every 0.15 seconds but I need it faster than that.
tool.Equipped:Connect(function()
equippedStatus = true
local Muzzle = player.Character.Blackout.Preview.MuzzleEffect
while equippedStatus == true do
wait(0.025)
Muzzle.Texture = "rbxassetid://421803006"
wait(0.05)
Muzzle.Texture = "rbxassetid://421803091"
wait(0.025)
Muzzle.Texture = "rbxassetid://421803134"
if player.Character.Blackout.ShootingStatus.Value == true then
MuzzleEvent:FireServer()
end
if player.Character.Blackout.ShootingStatus.Value == false then
MuzzleStopEvent:FireServer()
end
wait()
end
end)
while true do
if equippedStatus == true and not player.Character:FindFirstChild("Blackout") then
equippedStatus = false
end
wait()
end
I’ve printed out and tested the while loop below, equipped status changes from false to true depending on whether the player is actually holding the gun, like it’s supposed to.
why not just set “equippedStatus” whenever the gun is Equipped / Unequipped,
and then using RunService:BindToRenderStep() you can setup a loop that hits every frame?
tool.Equipped:Connect(function()
equippedStatus = true
end)
tool.Unequipped:Connect(function()
equippedStatus = false
end)
RunService:BindToRenderStep("swaws", function()
if equippedStatus then
-- Code here
end
end)
task.wait() can help a little, which you should be using anyway as wait() is deprecated and task.wait() is what replaced it.
task.wait() can run faster than wait(), so technically your loop should be able to run the same speed as RunService.Heartbeat, which is also faster than wait().
Your script is taking way longer cause you are doing a network call for each string of rbxassetid:// so instead of it waiting .05 seconds (the shortest would be .03) you are waiting your ping + roblox’s ping. Preload your textures
Looking at this code there are some things you might want to change:
First, the problem you’re looking to solve in your post, is that you need two loops instead of one. Animating the muzzle texture is delaying your loop.
You can create two loops like so:
task.spawn(function() -- task.spawn makes the function run asynchronously, so it doesn't stop the next bit of code from running
while conditional do
end
end)
task.spawn(function()
while conditional do
end
end)
The next thing you might want to change is how you do your events. It looks like you might be spamming the server with events currently. Instead, because events are guaranteed to get to the server, only send the events when there is a change.
That might look like this:
local lastValue = player.Character.Blackout.ShootingStatus.Value -- might need to add a not here to make it work initially
while equippedStatus == true do
if lastValue ~= player.Character.Blackout.ShootingStatus.Value then
if player.Character.Blackout.ShootingStatus.Value == true then
MuzzleEvent:FireServer()
end
if player.Character.Blackout.ShootingStatus.Value == false then
MuzzleStopEvent:FireServer()
end
end
lastValue = player.Character.Blackout.ShootingStatus.Value
end
The last thing which is pretty small is that you should probably using task.wait() instead of wait. It’s basically the same thing but better for performance.
Edit:
Actually I forgot about the limit on wait. The shortest time wait can wait for is 0.03 seconds. That means 4 waits results in 0.12 seconds. First thing you can do is remove the wait at the end since you have some at the top. Better thing to do is switch to task.wait() which has a shorter minimum wait time.
So I should put this code inside the two functions above, like this?
task.spawn(function()
local lastValue = not player.Character.Blackout.ShootingStatus.Value
while equipppedStatus == true do
if lastValue ~= player.Character.Blackout.ShootingStatus.value then
if player.Character.Blackout.ShootingStatus.Value == true then
MuzzleEvent:FireServer()
end
if player.Character.Blackout.ShootingStatus.Value == false then
MuzzleStopEvent:FireServer()
end
end
lastValue = player.Character.Blackout.ShootingStatus.Value
end
end
task.spawn(function()
--and what should I put here?
end
Yeah, sort of like that. I was thinking you could split your code for the logic from the animation:
tool.Equipped:Connect(function()
equippedStatus = true
local Muzzle = player.Character.Blackout.Preview.MuzzleEffect
task.spawn(function() -- task.spawn lets you run these two while loops without the first one stopping the second one.
while equippedStatus == true do
if player.Character.Blackout.ShootingStatus.Value == true then
MuzzleEvent:FireServer()
end
if player.Character.Blackout.ShootingStatus.Value == false then
MuzzleStopEvent:FireServer()
end
task.wait() -- Remember the wait to avoid a stack overflow
end
end)
task.spawn(function()
while equippedStatus == true do
task.wait(0.025) -- task.wait can stop for less than 0.3 seconds (wait can't)
Muzzle.Texture = "rbxassetid://421803006"
task.wait(0.05)
Muzzle.Texture = "rbxassetid://421803091"
task.wait(0.025)
Muzzle.Texture = "rbxassetid://421803134"
end
end)
end)