For i, v in pairs() Ended Up As A For Loop, How To Solve?

  1. What do you want to achieve? I want to create a for i, v in pairs() function to make a door closing function.

  2. What is the issue? The game treats my code as a for loop, which causes it to be repeated forever. Here’s the code:

a.Frame.DoorR.MouseButton1Click:Connect(function()
	if RDoorsOpen == true then
		RDoorsOpen = false
		for i, v in pairs(doors.R:GetDescendants()) do
			if v.Name == "Prismatic" then
				v.TargetPosition = 1.87
				a.Frame.DoorR.Text = "Closing Right Doors"
				wait(.9)
				for is, v in pairs(model:GetDescendants()) do
					if v.Name == "DoorClose" then
						v:Play()
						print("door close has played")
						for i, v in pairs(doors.R:GetDescendants()) do
							if v.Name == "Frame" then
								v.CanCollide = true
								a.Frame.DoorR.Text = "Open Right Doors"
								print("loop over")
							end
						end
					end
				end
			end
		end
	end
end)
  1. What solutions have you tried so far? I could not find any solutions on the DevForum.

Can you post where model is defined? Also show your explorer for doors.R?

I see you have a lot of loops inside loops, if there is only one descendant named “Prismatic” and/or “DoorClose” you could just use local v = doors.R:FindFirstChild("Prismatic", true)

If doors.R has a lot of descendants then this function will run exponentially long, for every child added it will take another n^2 cycles, widely regarded as a bad sign in performance.

1 Like

It’s difficult to know the exact issue without seeing the model hierarchy but I’d suggest an approach like this instead:

a.Frame.DoorR.MouseButton1Click:Connect(function()
	if RDoorsOpen == true then
		RDoorsOpen = false

		local prismaticDoor = doors.R:FindFirstChild("Prismatic", true)
		local doorClose = model:FindFirstChild("DoorClose", true)
		local frame = doors.R:FindFirstChild("Frame", true)

		if prismaticDoor and doorClose and frame then
			prismaticDoor.TargetPosition = 1.87
			a.Frame.DoorR.Text = "Closing Right Doors"
			task.wait(0.9)
			doorClose:Play()
			frame.CanCollide = true
			a.Frame.DoorR.Text = "Open Right Doors"
		end
	end
end)
2 Likes

heirarchy
The image is showing the hierarchy of where doors.R is located.
Model is defined as the model R9.
doors.R contains multiple "Prismatic"s and multiple "Frame"s and I want to change all of them simultaneously, which is why I chose to use for i, v in pairs().

There are multiple parts named “Prismatic”, “DoorClose”, and “Frame”.

Can you show at least one “Prismatic” and “Frame” in the explorer?

is doorClose a sound or a tween? If it’s a tween then it’s going to need to be ran for each individual door. Do you want these doors all closing at the same time (concurrently), or one after the other (sequentially)?

DoorClose is a sound, and I would like all the doors to close at the same time.

This will still need some tuning but it plays the sound once for all doors, and iterates over each Prismatic and after 0.9 seconds on each one it sets that door’s corresponding Frame.canCollide = true.

a.Frame.DoorR.MouseButton1Click:Connect(function()
	if RDoorsOpen == true then
		RDoorsOpen = false

		local doorClose = model:FindFirstChild("DoorClose", true)
		local doorClosePlayed = false

		for _, prismatic in doors.R:GetDescendants() do
			if prismatic.Name == "Prismatic" then
				prismatic.TargetPosition = 1.87

				-- Only play once for all the doors
				if not doorClosePlayed then
					doorClosePlayed = true
					doorClose:Play()
				end

				-- Set the door's frame to collide after 0.9 seconds
				task.delay(0.9, function()
					prismatic.Parent.Parent.Frame.CanCollide = true
				end)
			end
		end
	end
end)
1 Like

I have only one more issue… there are also multiple instances of DoorClose sound that I want to play simultaneously.

Where do they live in the object hierarchy? Are they inside Frame or Window? Let’s pretend they’re a child of frame. If so you could play it inside the task.delay()

prismatic.Parent.Parent.Frame.DoorClose:Play()

image (3)
They live inside a totally different area, still within original model. They are within Car1 and Car2.

Maybe it would be better to find those before the function call. (same with prismatic and frames) assuming they do not move in the hierarchy?

local doorSounds = {}
for _, doorSound in model:GetDescendants() do
    if doorSound.Name == "DoorClose" then
        table.insert(doorSounds, doorSound)
    end
end

a.Frame.DoorR.MouseButton1Click:Connect(function()
	if RDoorsOpen == true then
		RDoorsOpen = false
		for _, doorSound in doorSounds do
			doorSound:Play()
		end
1 Like

None of these solutions truly worked, and were either extremely buggy, or didn’t do what I want. I was able to apply concepts, however, to create a script that would go around having to put for loops inside of eachother.

Final Script:

a.Frame.DoorR.MouseButton1Click:Connect(function()
	if RDoorsOpen == true then
		RDoorsOpen = false
		a.Frame.DoorR.Text = "Closing Right Doors"
		for i, v in pairs(doors.R:GetDescendants()) do
			if v.Name == "Prismatic" then
				v.TargetPosition = 1.86
			end
		end
		for i, v in pairs(model:GetDescendants()) do
			if v.Name == "DoorClose" then
				v:Play()
			end
		end
		wait(0.9)
		a.Frame.DoorR.Text = "Open Right Doors"
		for i, v in pairs(doors.R:GetDescendants()) do
			if v.Name == "Frame" then
				v.CanCollide = true
			end
		end
	elseif RDoorsOpen == false then
		RDoorsOpen = true
		a.Frame.DoorR.Text = "Opening Right Doors"
		for i, v in pairs(doors.R:GetDescendants()) do
			if v.Name == "Prismatic" then
				v.TargetPosition = 0
			end
		end
		for i, v in pairs(doors.R:GetDescendants()) do
			if v.Name == "Frame" then
				v.CanCollide = false
			end
		end
		for i, v in pairs(model:GetDescendants()) do
			if v.Name == "Open" then
				v:Play()
			end
		end
		wait(0.9)
		a.Frame.DoorR.Text = "Close Right Doors"
	end
end)
2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.