How to have 1 script reference multiple of the same model

I have multiple elevators in a building. Each floor has 3 elevators, and each elevator is it’s own model. 6 floors with 3 elevators on each floor means 18 elevator models. Inside each model is a button to open the elevator doors (inside this button is a ClickDetector)

The problem I am facing is having 1 script handle all of these elevators. Atm I have 16 scripts inside each model. This is becomming a real hassle, as if I want to add more code to it later on, or something breaks, then I have to go and make the changes to all 16 scripts.

local model = script.Parent

local button = model.Button
local clickDetector = button.ClickDetector

local doorLeft = model.DoorLeft
local doorRight = model.DoorRight

local opened = false
local debounce = false

clickDetector.MouseClick:Connect(function()
	if debounce then return end
	
	debounce = true
	
	if opened then
		opened = false
		for i = 1, 20 do
			doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, 0.2)
			doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, -0.2)
			wait()
		end
	else
		opened = true
		for i = 1, 20 do
			doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, -0.2)
			doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, 0.2)
			wait()
		end
	end
	debounce = false
end)

This is my current code. Nothing broken with it, but just don’t know how to get the script to reference every single elevator model

4 Likes

Try requring module scripts from each of the scripts, then you can edit the module script instead.

2 Likes

There are multiple ways to do this, simplest being, put them all in a folder or whatsoever and loop over it.

local folder = pathtofolder

for _,v in pairs(folder:GetChildren()) do

	local model = v
	
	local button = model.Button
	local clickDetector = button.ClickDetector
	
	local doorLeft = model.DoorLeft
	local doorRight = model.DoorRight
	
	local opened = false
	local debounce = false
	
	clickDetector.MouseClick:Connect(function()
		if debounce then return end
		
		debounce = true
		
		if opened then
			opened = false
			for i = 1, 20 do
				doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, 0.2)
				doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, -0.2)
				wait()
			end
		else
			opened = true
			for i = 1, 20 do
				doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, -0.2)
				doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, 0.2)
				wait()
			end
		end
		debounce = false
	end)
	
end
10 Likes

Have you ever tried TweenService? That worked for me every single time:circles

This is a .gif showing the power of TweenService with the gates.

Best method to organize these scripts is to sort all into a ModuleScript, a little bit of logic can solve the problem.

5 Likes

From what @Nitefal mentioned, you could additionally put a tag using CollectionService and put in the same loop as what Nitefal mentioned. To make sure the game has loaded, use a :GetPropertyChangedSignal event on game.Loaded to see if the game make sure the game has loaded so you don’t miss out on a model.

1 Like

Assuming all the tags have been set offline, there’s no reason why CollectionService::GetTagged would miss an instance. If instances are dynamically added/removed, GetInstanceAddedSignal and GetInstanceRemovedSignal can be used to keep track of em.

@op: Should you choose to use the CollectionService instead…

local CollectionAPI = game:GetService("CollectionService")

local CollectionTag = "Elevator"
local CreatedSignal = CollectionAPI:GetInstanceAddedSignal(CollectionTag)
local DeletedSignal = CollectionAPI:GetInstanceRemovedSignal(CollectionTag)

local GetAllTagged = CollectionAPI:GetTagged(CollectionTag)

local Elevators do
	Elevators = {}
	
	function Operate(elevator) 
		print(elevator:GetFullName()) --// elevator code
	end
		
	local function tagAdded(instance)
		--// new tag dynamically added
		Elevators[#Elevators+1] = Operate(instance)
	end
	
	local function tagRemoved(instance)
		if Elevators[instance] then
			Elevators[instance] = nil;
		end	
	end
	
	for i = 1, #GetAllTagged do
		tagAdded((GetAllTagged[i]))
	end
	
	CreatedSignal:Connect(tagAdded)
	DeletedSignal:Connect(tagRemoved)
end

Every edit to the Operate function would apply to all models/instances with the tag Elevator. I don’t know if there’s been an official one since, but this tag editor can be used to visualize and properly assign tags in Studio.

1 Like

The script could run before other models get the chance to load their descendent(s)

If you were to use a script inside the models to add the tags

Right - yeah I suppose. That can still be easily managed though with CollectionAPI::GetInstanceAddedSignal, assuming, like you said, that the script itself isn’t in a position where it might be slow to load or replicate.

1 Like

Works :smiley: getting new problems no however if I have more buttons inside the elevator

local elevators = workspace.Elevators

function open(doorLeft, doorRight)
	for i = 1, 20 do
		doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, -0.2)
		doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, 0.2)
		wait()
	end
		
	wait(2)
		
	for i = 1, 20 do
		doorLeft.CFrame = doorLeft.CFrame + Vector3.new(0, 0, 0.2)
		doorRight.CFrame = doorRight.CFrame + Vector3.new(0, 0, -0.2)
		wait()
	end
end

for _, elevator in pairs(elevators:GetChildren()) do
	local button = elevator.Button
	local openDetector = button.ClickDetector
	
	local doorLeft = elevator.DoorLeft
	local doorRight = elevator.DoorRight
	
	local debounce = false
	print(1)
	openDetector.MouseClick:Connect(function()
		print(2)
		if debounce then return end
		
		debounce = true
		
		open(doorLeft, doorRight)
				
		debounce = false
	end)
	
	for _, buttons in pairs(elevator:GetChildren()) do
		if buttons:FindFirstChild('ClickDetector') and buttons.Name ~= 'Button' then
			openDetector.MouseClick:Connect(function()
				if debounce then return end
				
				debounce = true
				
				print('Going up to', buttons.Name)
				
				wait(2)
				
				debounce = false
			end)
		end
	end
end

What this is trying to do is openDetector is the the ClickDetector that’s inside the button that opens the elevator. However, the elevator also has buttons inside it, which are used to go up and down floors. That’s what the second for loop is for. When I click the open button however, it prints ‘Going up to 6’ and then ‘2’. However, when I click the open button, it should not be getting access to the second function, as I have

if buttons:FindFirstChild('ClickDetector') and buttons.Name ~= 'Button' then

Which finds the other buttons, but does not include the open door button

EDIT Nvm I found the problem :stuck_out_tongue:

1 Like