Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How do you disconnect events? Stacking them is causing major lag

Asked by
ItsMeKlc 235 Moderation Voter
7 years ago
Edited 7 years ago

So for an inventory I'm creating I need it to update the hot bar you know, to do that I'm using a changed event. The problemo is that if you keep using it it'll start to lag because the events keep stacking up. I need to know how to disconnect events.

(Not the entire script, just parts I think you'll need for context)

function update()
    print("Prime update")
    if script.Parent.Image == "" then
        script.Parent.Amount.Visible = false
    else
        if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil and  player.Inventory[script.Parent.Item.Value].Value == 0 then
            script.Parent.Amount.Visible = false
            script.Parent.Image = ""
            script.Parent.Item.Value = ""
        elseif player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
            script.Parent.Amount.Visible = true
            script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value
            if a~=nil then
                a = nil
            end         
            local a = player.Inventory[script.Parent.Item.Value].Changed:connect(update)
        end
    end
end

[Completed fixed version]

local player = script.Parent.Parent.Parent.Parent.Parent.Parent.Parent
local a = nil
function onClicked()
    if script.Parent.Image~="" then 
        if game.Workspace:WaitForChild(player.Name):FindFirstChild(script.Parent.Item.Value)~=nil then
            game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
        else
            game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
            game.Workspace:WaitForChild(player.Name).Humanoid:EquipTool(game.ReplicatedStorage.assets.Items[script.Parent.Item.Value]:Clone())
        end
        local kids = player.Backpack:GetChildren()
        for i=1,#kids do
            if kids[i].ClassName == "Tool" then
                kids[i]:Destroy()
            end
        end
    elseif script.Parent.Image == "" then
        game.Workspace:WaitForChild(player.Name).Humanoid:UnequipTools()
    end
end

function update()
    print("Prime update")
    if script.Parent.Image == "" then
        script.Parent.Amount.Visible = false
        if a~=nil then
            a:disconnect()
        end     
    else
        if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil and  player.Inventory[script.Parent.Item.Value].Value == 0 then
            script.Parent.Amount.Visible = false
            script.Parent.Image = ""
            script.Parent.Item.Value = ""
        elseif player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
            script.Parent.Amount.Visible = true
            script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value       
        end
    end
end

script.Parent.Item.Changed:connect(function()
    if a~=nil then
        a:disconnect()
    end
    if script.Parent.Item.Value~="" then
        a = player.Inventory[script.Parent.Item.Value].Changed:connect(update)
    end
end)

userInput = game:GetService("UserInputService")
userInput.InputBegan:connect(function(input)
    if input.UserInputType == Enum.UserInputType.Keyboard and input.UserInputState == Enum.UserInputState.Begin and input.KeyCode == Enum.KeyCode.One then

        onClicked()

    end
end)

game.Players.LocalPlayer.CharacterAdded:connect(function(character)
    update()
end)

script.Parent.MouseButton1Click:connect(onClicked)
script.Parent.Changed:connect(update)

wait(10)
update()
if player.Inventory:FindFirstChild(script.Parent.Item.Value)~=nil then
    script.Parent.Amount.Text = "x"..player.Inventory[script.Parent.Item.Value].Value
else
    script.Parent.Amount.Text = ""
end

2 answers

Log in to vote
2
Answered by 7 years ago
Edited 7 years ago

You never need more than one event for the same job


If you're ever in a situation where you're connecting multiple events to the same object within a loop, another event, or multiple times without disconnecting them, you need to fix that immediately. When setting up an event listener, ROBLOX does not overwrite the previous one (as you've probably figured out).

Instead, you need to disconnect the previous event manually if you're going to be throwing it away, or connecting more of the same events to the object. You can do this by using the disconnect method on what your connect method returns. Here's an example:

-- "PartTouched" now represents what "connect()" returns, which is the event signal for this individual event.
local PartTouched = Part.Touched:connect(function()
    print("Part touched")
end)

-- Once you have a reference to that signal, you can then disconnect it by calling the "disconnect()" method on it whenever you want.
PartTouched:disconnect()

Only firing once

Now, sometimes you only want an event to fire once at a time. You could use a debounce strategy, which is probably better 90% of the time. But for that specific situation where the event must be disconnected right after it fires, this is how it'd be done:

  • A reference to the event must be defined outside it's callback function

    • You could avoid doing this by using a global variable (i.e, a non-local variable), but that's not good practice. What you should do, is define a local variable with no value to tell the script you're going to assign something to it later.
  • Disconnect the event as soon as it fires

    • In case something might fire your event twice immediately and your code yields at some point before disconnecting the event, you should always disconnect it before doing anything else.

Understanding this, here's an example of how it'd be done:

-- Making the local variable "PartTouched" with a default value of nil. Now we can reference this variable outside our callback function we pass to the event
local PartTouched

PartTouched = Part.Touched:connect(function()
    -- We can disconnect it, since we set it to the signal the event returns
    PartTouched:disconnect()

    -- The rest of your code
    print("Hello")
end)

While disconnecting events is important if you're going to be using creating more than one for the same object, it can also be unnecessary in avoidable situations. Most of the time, you can just have one event constantly listening for something without needing to mess with disconnect or debounce. In the case of your code, this can be implemented by simply taking your event connection out of your update function, and have it somewhere where it's only going to be created that one time.

Hope that helped, if you have any questions or if anything was unclear, just let me know and I'll get back to you as soon as possible.

0
The reason why I'm doing it this way is because the item there changes and I don't want it to go through all 100+ items in my game just to get this one thing. I tried putting a:disconnect() on line 14 but it didn't work. Am I using it incorrectly? ItsMeKlc 235 — 7y
Ad
Log in to vote
-3
Answered by 7 years ago

Just put something like this in:

myFunction:disconnect()

Substitute 'myFunction' for the name of the function you want to disconnect.

0
You don't disconnect the function, you disconnect the signal the connect method returns. ScriptGuider 5640 — 7y
0
I put 'a:disconnect()' on line 14 and it didn't help ItsMeKlc 235 — 7y

Answer this question