I’m making a ModuleScript which toggles an alarm feature, which is just playing an alarm sound and looping the part’s material.
It works when I toggle the alarm on, but when I try to turn it off, it keeps looping the materials. Is there any way I could break this loop?
function Main.ToggleAlarm(part)
local alarmOff = true
if alarmOff then
part.Alarm:Play()
while true do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
alarmOff = false
else
if alarmOff == false then
part.Alarm:Stop()
part.Material = Enum.Material.SmoothPlastic
alarmOff = true
end
end
end
You have a while true loop which doesn’t have a break statement in it. This means you will never exit this loop.
Edit: You may also simplify your code a bit:
function Main.ToggleAlarm(part)
local alarmOff = not part.Alarm.IsPlaying -- If alarm is playing, then the alarm is on.
if alarmOff then
alarmOff = false -- You turn on the alarm here
part.Alarm:Play()
while part.Alarm.IsPlaying do -- Loop until it stops playing
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
else -- You will only end up in the else statement if alarmOff == false
part.Alarm:Stop()
part.Material = Enum.Material.SmoothPlastic
alarmOff = true
end
end
Hi r_aikkonen - the easiest way to break this loop would be to create a bindable event, fire that event in the else section of your if statement, and then put this line at the end of your while loop:
Event.Event:Connect(function()
break
end)
Alternatively you could change the loop to a repeat until loop and just repeat until the event id fired.
if alarmOff then
part.Alarm:Play()
alarmOff = false
while alarmOff == false do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
Is there a line that changes the alarmOff to true once you want to stop it? Also, I would recommend putting the while loop inside a coroutine like this
coroutine.wrap(function()
while alarmOff == false do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
end)()
If there is no coroutine, the code will just keep the loop going, without being able to do anything else. If you put it in a coroutine, it will be able to execute other codes inside the same script, while the loop still runs.
local Main = {}
function Main.ToggleAlarm(part)
local alarmOff = true
if alarmOff then
part.Alarm:Play()
alarmOff = false
coroutine.wrap(function()
while alarmOff == false do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
end)()
else
if alarmOff == false then
part.Alarm:Stop()
part.Material = Enum.Material.SmoothPlastic
alarmOff = true
end
end
end
return Main
If you set the alarmOff true at the beginning, there is no way that the second part of the if statement could run, and it won’t set the alarmOff to true again.
local alarmOff = true
function Main.ToggleAlarm(part)
if alarmOff then
part.Alarm:Play()
alarmOff = false
coroutine.wrap(function()
while not(alarmOff) do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
end)()
else
part.Alarm:Stop()
part.Material = Enum.Material.SmoothPlastic
alarmOff = true
end
end
I moved the local alarmOff = true to the outside of the function. Now it’s able to run the second part too.
Also, I removed the if alarmOff == false from the second part, because it had no meaning. If you check if it’s true, and it’s not, you don’t need to check if it’s false again, because you already know that it is. That’s how the if statement works
I’m aware that that’s how it works, I’ve just had trust issues with if else statements, so I put another condition just to double check it.
Now what happens is if I click an alarm to enable it, it works fine, but if I click another alarm, It stops the enabled one blinking and continues to beep.
if you have multiple alarms, you have to store their “alarmOff” state individually. Create a BoolValue inside each of the alarms, set them true by default, and then do this
function Main.ToggleAlarm(part)
local alarmOff = part.alarmOff
if alarmOff.Value then
part.Alarm:Play()
alarmOff.Value = false
coroutine.wrap(function()
while not(alarmOff.Value) do
part.Material = Enum.Material.Neon
wait(part.Alarm.TimeLength/2)
part.Material = Enum.Material.SmoothPlastic
wait(part.Alarm.TimeLength/2)
end
end)()
else
part.Alarm:Stop()
part.Material = Enum.Material.SmoothPlastic
alarmOff.Value = true
end
end