Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Touched event firing multiple times for one part?

I'm having trouble with the Touched event. Essentially I'm trying to make interact-able (?) shops. When the player touches an invisible part the script displays a prompt ("Press E to interact"). When the player presses E it then displays the shop GUI.

The prompt should obviously disappear once the player has pressed E and it should un-queue the E key from ContextActionService, however it appears this isn't happening every time - sometimes if you press E the prompt will stay on screen and then disappears when you press E a second time.

I added a couple of print()s with timestamps and it looks like the Touched event is being fired multiple times (particularly when walking through the invisible part) causing the PROMPT.SHOW() function to run multiple times as well.

Is there a fix for this or am I better moving away from the Touched event altogether? If so what is the best/most efficient alternative? Code is below, thanks

local INPUT = game:GetService("ContextActionService")

local PLAYER = game:GetService("Players").LocalPlayer
local CHARACTER = PLAYER.Character
local TORSO = CHARACTER:WaitForChild("HumanoidRootPart")

local ALL_SHOPS = game.Workspace:WaitForChild("Shops")

local TOUCHING = nil

local function OPEN_SHOP(_, STATE)
    if STATE == Enum.UserInputState.Begin then
	    INPUT:UnbindAction("OpenShop")
	    local HUMANOID = CHARACTER:WaitForChild("Humanoid")
	    local LAST_WALKSPEED = HUMANOID.WalkSpeed
	    HUMANOID.WalkSpeed = 0
		HUMANOID:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
	    script.Parent.Prompt.Visible = false
	    
	    local UI = script.Parent.Frame
	    UI.ExitBtn.MouseButton1Down:Connect(function()
		    UI.Visible = false
		    if TOUCHING ~= nil then
			    INPUT:BindAction("OpenShop", OPEN_SHOP, false, Enum.KeyCode.E)
			    script.Parent.Prompt.Visible = true
		    end
		    HUMANOID.WalkSpeed = LAST_WALKSPEED
			HUMANOID:SetStateEnabled(Enum.HumanoidStateType.Jumping, true)
	    end)
	    UI.ScrollingFrame:ClearAllChildren()
	    UI.TotalTxt.Text = "Total: £0.00"
	    UI.ShopNameTxt.Text = TOUCHING.Parent.Name
	    local ITEMS = require(TOUCHING.ModuleScript)
	    for i, details in pairs(ITEMS) do
		    local FRAME = script.ItemFrame:Clone()
		    FRAME.Position = UDim2.new(0, 0, 0, FRAME.Size.Y.Offset * (i - 1))
		    FRAME.ImageLabel.Image = details[2] or FRAME.ImageLabel.Image
		    FRAME.ItemTxt.Text = "£"..tostring(math.floor(details[3] * 100) / 100).." "..details[1]
		    FRAME.Parent = UI.ScrollingFrame
	    end
	    UI.Visible = true
    end
end
local PROMPT = {
    SHOW = function()
	    print("Showed prompt @ "..os.time())
	    INPUT:BindAction("OpenShop", OPEN_SHOP, false, Enum.KeyCode.E)
	    script.Parent.Prompt.Visible = true
    end,
    HIDE = function()
	    INPUT:UnbindAction("OpenShop")
	    script.Parent.Prompt.Visible = false
    end,
}

TORSO.Touched:Connect(function(newPart)
    print("Touched new part: "..newPart.Name)
    if newPart:IsDescendantOf(ALL_SHOPS) and TOUCHING == nil then
	    TOUCHING = newPart
	    PROMPT.SHOW()
    end
end)
TORSO.TouchEnded:Connect(function(oldPart)
    if oldPart == TOUCHING then
	    TOUCHING = nil
	    PROMPT.HIDE()
    end
end)

1 comment

0

add a debounce here is a vid on how to use debounce if u dont know already: https://www.youtube.com/watch?v=HoZkuvd6RPA&t=0s

1 answer

Answered on Discord, thanks to NewVoids. I added another print() to the TouchEnded event which it turns out was also firing which was setting TOUCHING to nil which is why the Touched event wasn't stopped by the if statement checking if TOUCHING == nil.

It's not a solution as such but as a workaround rather than just doingif oldPart == TOUCHING then I instead used GetTouchingParts(), looped through all the parts touching the HumanoidRootPart, and if it included the invisible shop part I return'd to terminate the function. Entire script is the same save for this last bit:

TORSO.TouchEnded:Connect(function()
    for _, part in pairs(TORSO:GetTouchingParts()) do
	    if part == TOUCHING then return end
	end
	-- From here on won't run if the torso is still touching the invisible shop part!
	TOUCHING = nil
	PROMPT.HIDE()
end)

1 comment

0

put "[Solved]" in the title

This discussion is preserved as it was. New answers, comments, and votes are closed.