Creating one server script to manage many buttons being potentially touched

So I want to create a server script that manages multiple buttons instead of a unique script for each button.

I’ve tried to use CollectionService to tag every button, but it results in every button acting as if it was touched simultaneously. (Tagged every button with “Button”, looped through all tagged buttons to connect them to Touched event)

Is there a better way to do this, preferably without something like OOP?

EDIT: Code as requested

local CollectionService = game:GetService("CollectionService")
local LargeNumbers = require(game:GetService("ReplicatedStorage"):WaitForChild("LargeNumbers"))

local Connections = {}

local function Purchase(Player, Config)
    print('test')
end

---

local function InstanceAdded(ins)
	if ins:IsA("BasePart") and ins:FindFirstChild("Configuration") then 
		Connections[ins] = ins.Touched:Connect(Purchase)
		print(Connections[ins], #Connections)
	end
end

local function InstanceRemoved(ins)
	if Connections[ins] then Connections[ins]:Disconnect() Connections[ins] = nil end
end

CollectionService:GetInstanceAddedSignal("Button"):Connect(InstanceAdded)

for i, v in pairs(CollectionService:GetTagged("Button")) do
	InstanceAdded(v)
end

---

for i, v in pairs(workspace:GetDescendants()) do
	if v:IsA("BasePart") and v:FindFirstChild("Configuration") then
		CollectionService:AddTag(v, "Button")
	end
end

---

wait(3)
print("Made " .. #Connections .. " connections")

Interestingly enough, #Connections print 0.
Output is initially “test x9” (there are 9 buttons), and significantly increases when player is near/touching any button

I believe if you posted a visual (i.e., code and output (NOT as an image)) that would help a lot.

1 Like

It’s because you have a dictionary, and the # operator only gets the length of the array part of a table.

2 Likes

Oh, duh. I should have figured, lol.
Was just a debug to test the amount of connections. Every button is connected but they all seem to function as a single unit compared to individually

In case you need to know ‘which particular part/object was touched’ in your general method, then I suggest using an anonymous function, so it can “transfer” the knowledge of the part/object together with what is touching it:

Connections[ins] = ins.Touched:Connect(
  function(other)
    Purchase(ins, other)
  end
)

And then change your general Purchase method to something like:

local Players = game:GetService("Players")

local function Purchase(button, otherPart)
  -- Make sure this `button` actually has a configuration
  local config = button and button:FindFirstChild("Configuration")
  if nil ~= config then
    -- Find player that touched it
    local otherModel = otherPart and otherPart:FindFirstAncestorWhichIsA("Model")
    local player = otherModel and Players:GetPlayerFromCharacter(otherModel)
    if nil ~= player then
      print("Player ",player," touched ",button)
    end
  end
end

You should definitively also add some kind of debounce / ‘stop-too-many-touch-events’ functionality, to avoid getting the Touched-event fired continuously, when each part (that a player-character-humanoid consist of) is (re-) touching the part/object.

1 Like