Debounce: Difference between revisions

From Legacy Roblox Wiki
Jump to navigationJump to search
>KnKGames.Com
No edit summary
m Text replacement - "</SyntaxHighlight>" to "</syntaxhighlight>"
 
(64 intermediate revisions by 12 users not shown)
Line 1: Line 1:
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
A '''debounce''' system is a set of code that keeps a function from running too many times. It comes from the idea of mechanical switch bounce, where a switch bounces when pushed, creating multiple signals. In the context of ROBLOX, this problem occurs mainly with the [[Touched]] event, when a part touches another multiple times in a short space of time, but may be useful in other cases as well.
I am permantly banned from roblox!
==Theory==
Let's say you have a button on the floor. When you jump on the button, it prints a message to the output. Your code would look like this:


Please Spread The Word!
<syntaxhighlight lang="lua">
Workspace.Button.Touched:connect(function(hit)
    print("Button pressed") --Print the message
    wait(1)                --Wait for 1 second
    print("Hi :D")          --Print another message
end)
</syntaxhighlight>


This will put this message in the output:
<syntaxhighlight lang="lua">
Button pressed
Hi :D
</syntaxhighlight>
The problem is that because of the way the physics engine handles the collision, it will not register just one collision, but may cause several Touched events to fire, so your output will look more like this:
<code>
Button pressed
Button pressed
Button pressed
Button pressed
Button pressed
Hi :D
Hi :D
Hi :D
Hi :D
Hi :D
</syntaxhighlight>
Rather than executing sequentially, all the event handlers execute at the same time.


Here is a possible scenario you may encounter:


Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
If you're using a button to [[How to Make a Model Regenerate|regenerate a model]] then it will make 5 of whatever you are regenerating. This is an issue because ''all 5 will be in the same spot'' causing all kinds of problems. This can problem can easily be avoided by using a simple debounce system in your code. Of course, you could use a [[ClickDetector]] for your button, which would correct the problem, but you can't always use ClickDetectors, so sometimes, a debounce would be useful.
I am permantly banned from roblox!


Please Spread The Word!
This is how a basic debounce system works:


Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
When an action happens, such as someone pressing your floor button, the script '''locks''' any new function calls until a time passes or the action is complete.
I am permantly banned from roblox!


Please Spread The Word!
==Use Case==
It's fairly simple to convert an existing script to using debounce. Let's use the same script we had above, and add a couple of lines. In this case we will put in a time limit to wait for until the function can be run again.


Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
<syntaxhighlight lang="lua">
I am permantly banned from roblox!
local buttonPressed = false
--Store whether the button is pressed in a local variable


Please Spread The Word!
Workspace.Button.Touched:connect(function(hit)
    if not buttonPressed then
    -- Is it not pressed?


Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
        buttonPressed = true
I am permantly banned from roblox!
        -- Mark it as pressed, so that other handlers don't execute


Please Spread The Word!
        print("Button pressed")
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
        wait(1)
I am permantly banned from roblox!
        print("Hi :D")
        -- Do Stuff


Please Spread The Word!
        buttonPressed = false
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
        -- Mark it as not pressed, so other handlers can execute again
I am permantly banned from roblox!
    end
end)
</syntaxhighlight>


Please Spread The Word!
This will cause your output to look like this:
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
<code>
I am permantly banned from roblox!
Button pressed
Hi :D
</syntaxhighlight>


Please Spread The Word!
That's more like it! You can use this same concept, by adding the same 4 lines to different scripts, in most any script involving functions. It doesn't even have to just be touched objects, it can be used to keep people from pressing a button more than once, firing a weapon more often than you want, or preventing a new event from happening before the old one is done. Take a look at the next example.
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
I am permantly banned from roblox!


Please Spread The Word!
==Real World==
Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
I am permantly banned from roblox!


Please Spread The Word!Attention Everyone: I did not phish Roni123’s acount! Someone hacked knkgames.com! Talk to Roni123 for more details!
Here's the Local Gui script of the Rocket Launcher tool:
I am permantly banned from roblox!


Please Spread The Word!
<syntaxhighlight lang="lua">
enabled = true
function onButton1Down(mouse)
    if not enabled then
        return
    end
 
    enabled = false
    mouse.Icon = "rbxasset://textures\\GunWaitCursor.png"
 
    wait(12)
    mouse.Icon = "rbxasset://textures\\GunCursor.png"
    enabled = true
 
end
</syntaxhighlight>
 
When you fire a rocket, the script shows the reload icon. Then the function waits for 12 seconds. During this time, enabled is false, so if the player tries to fire another rocket, the script won't run because the function will just return right away. After the 12 seconds are up, the reload cursor goes away and enabled becomes true again, allowing the user to fire another rocket.
 
==Advanced notation==
 
After a while, it might get tedious defining a separate debounce variable for each event handler. Instead, you can write a debounce function, that returns a debounced copy of its first argument.
 
<syntaxhighlight lang="lua">
function debounce(func)
    local isRunning = false    -- Create a local debounce variable
    return function(...)      -- Return a new function
        if not isRunning then
            isRunning = true
 
            func(...)          -- Call it with the original arguments
 
            isRunning = false
        end
    end
end
</syntaxhighlight>
 
Applying this to the original code:
 
<syntaxhighlight lang="lua">
Workspace.Button.Touched:connect(debounce(function(hit)
    print("Button pressed") --Print the message
    wait(1)                --Wait for 1 second
    print("Hi :D")          --Print another message
end))
</syntaxhighlight>
 
[[Category:Scripting Tutorials]]

Latest revision as of 06:05, 27 April 2023

A debounce system is a set of code that keeps a function from running too many times. It comes from the idea of mechanical switch bounce, where a switch bounces when pushed, creating multiple signals. In the context of ROBLOX, this problem occurs mainly with the Touched event, when a part touches another multiple times in a short space of time, but may be useful in other cases as well.

Theory

Let's say you have a button on the floor. When you jump on the button, it prints a message to the output. Your code would look like this:

Workspace.Button.Touched:connect(function(hit)
    print("Button pressed") --Print the message
    wait(1)                 --Wait for 1 second
    print("Hi :D")          --Print another message
end)

This will put this message in the output:

Button pressed
Hi :D

The problem is that because of the way the physics engine handles the collision, it will not register just one collision, but may cause several Touched events to fire, so your output will look more like this: Button pressed Button pressed Button pressed Button pressed Button pressed Hi :D Hi :D Hi :D Hi :D Hi :D </syntaxhighlight> Rather than executing sequentially, all the event handlers execute at the same time.

Here is a possible scenario you may encounter:

If you're using a button to regenerate a model then it will make 5 of whatever you are regenerating. This is an issue because all 5 will be in the same spot causing all kinds of problems. This can problem can easily be avoided by using a simple debounce system in your code. Of course, you could use a ClickDetector for your button, which would correct the problem, but you can't always use ClickDetectors, so sometimes, a debounce would be useful.

This is how a basic debounce system works:

When an action happens, such as someone pressing your floor button, the script locks any new function calls until a time passes or the action is complete.

Use Case

It's fairly simple to convert an existing script to using debounce. Let's use the same script we had above, and add a couple of lines. In this case we will put in a time limit to wait for until the function can be run again.

local buttonPressed = false
--Store whether the button is pressed in a local variable

Workspace.Button.Touched:connect(function(hit)
    if not buttonPressed then
    -- Is it not pressed?

        buttonPressed = true
        -- Mark it as pressed, so that other handlers don't execute

        print("Button pressed")
        wait(1)
        print("Hi :D")
        -- Do Stuff

        buttonPressed = false
        -- Mark it as not pressed, so other handlers can execute again
    end
end)

This will cause your output to look like this: Button pressed Hi :D </syntaxhighlight>

That's more like it! You can use this same concept, by adding the same 4 lines to different scripts, in most any script involving functions. It doesn't even have to just be touched objects, it can be used to keep people from pressing a button more than once, firing a weapon more often than you want, or preventing a new event from happening before the old one is done. Take a look at the next example.

Real World

Here's the Local Gui script of the Rocket Launcher tool:

enabled = true
function onButton1Down(mouse)
    if not enabled then
        return
    end

    enabled = false
    mouse.Icon = "rbxasset://textures\\GunWaitCursor.png"

    wait(12)
    mouse.Icon = "rbxasset://textures\\GunCursor.png"
    enabled = true

end

When you fire a rocket, the script shows the reload icon. Then the function waits for 12 seconds. During this time, enabled is false, so if the player tries to fire another rocket, the script won't run because the function will just return right away. After the 12 seconds are up, the reload cursor goes away and enabled becomes true again, allowing the user to fire another rocket.

Advanced notation

After a while, it might get tedious defining a separate debounce variable for each event handler. Instead, you can write a debounce function, that returns a debounced copy of its first argument.

function debounce(func)
    local isRunning = false    -- Create a local debounce variable
    return function(...)       -- Return a new function
        if not isRunning then
            isRunning = true

            func(...)          -- Call it with the original arguments

            isRunning = false
        end
    end
end

Applying this to the original code:

Workspace.Button.Touched:connect(debounce(function(hit)
    print("Button pressed") --Print the message
    wait(1)                 --Wait for 1 second
    print("Hi :D")          --Print another message
end))