Help with detecting multiple object in a folder

Hey, I am trying to make a press “F” to sit type of script and but I am having a small issue where I couldn’t detect all the seats inside a folder. How can I improve my scripts to make them work?

Screenshot_231
https://gyazo.com/d89ce5decb7dd729032721ac815bb4f8

The code:

for i, v in pairs(workspace.SeatFolder:GetChildren())do
while wait()do
if v and (player.Character.PrimaryPart.Position - v.Position).Magnitude < distance then
tween:Play()
Button.Button.Text = “F - Sit”
Button.Adornee = v
else
tween2:Play()
wait(.5)
Button.Button.Text = “”
Button.Adornee = nil
end
end
end

Any help would be useful and thanks!

for i, v in pairs(workspace.SeatFolder:GetChildren())do
	coroutine.resume(coroutine.create(function()
		while wait()do
			if v and (player.Character.PrimaryPart.Position - v.Position).Magnitude < distance then
				tween:Play()
				Button.Button.Text = "F - Sit"
				Button.Adornee = v
			else
				tween2:Play()
				wait(.5)
				Button.Button.Text = ""
				Button.Adornee = nil
			end
		end
	end))
end

You need to add the while loop into a coroutine because the while loop will only allow one seat to be detected and won’t let the for loop to go to the other seats

2 Likes

Time to do some more research on the coroutine! Thank you.

1 Like

I noticed something, its working as intended but the animation of the tween keep on playing. Any idea on how to fix it?

If you want an explanation to @Tommybridge’s solution:

What he added was a coroutine, which basically ran in a different thread than the main script.
Think of it like “multiple scripts in one script”, so he’s running the while loop in different threads so it will not yield the entire script, only the new thread.

1 Like

Spawn() is also an alternative option if you don’t feel like typing out that entire line. Does the same exact thing in this particular context. Coroutines could be the better option in a different scenario.

This topic explains the difference really well if you want to read through it.

1 Like

You’re calling Tween:Play() every time the while loop passes.
What I’d do is make two variables: ‘State’, and ‘PreviousState’ which would just be either 1 or 2.
State ‘1’ means it’s found a seat, where ‘2’ means it hasn’t.
Then before you call Tween:Play(), check if the current State is NOT equal to PreviousState, this will indicate a state change and you can set PreviousState to the current one.

1 Like

EDIT: There’s a wait .5 thingy, forgot to do that…

local State,PreviousState = 0,0

local Callbacks = {
	[1] = function() -- State 1
		Button.Button.Text = "F - Sit"
		Button.Adornee = v
	end;
	[2] = function()
		Button.Button.Text = ""
		Button.Adornee = nil
	end;
}

for i, v in pairs(workspace.SeatFolder:GetChildren())do
	spawn(function()
		while wait() do

			local WaitTime = 0;

			if v and (player.Character.PrimaryPart.Position - v.Position).Magnitude < distance then
				State = 1
			else
				State = 2
				WaitTime = .5
			end

			local TweenToPlay = State == 1 and tween or State == 2 and tween2
			if (PreviousState ~= State) then
				TweenToPlay:Play()
				wait(WaitTime)
				(Callbacks[State])()
			end

			PreviousState = State
		end
	end)
end

Try using PlaybackState:

for i, v in pairs(workspace.SeatFolder:GetChildren())do
	coroutine.resume(coroutine.create(function()
		while wait()do
			if v and (player.Character.PrimaryPart.Position - v.Position).Magnitude < distance then
				if tween.PlaybackState ~= Enum.PlaybackState.Playing then
					tween:Play()
					Button.Button.Text = "F - Sit"
					Button.Adornee = v
				end
			else
				if tween2.PlaybackState ~= Enum.PlaybackState.Playing then
					tween2:Play()
					wait(.5)
					Button.Button.Text = ""
					Button.Adornee = nil
				end
			end
		end
	end))
end

Edit: This won’t work, it will just loop the tween.

PlaybackState wouldn’t work, it’d still be repetitively calling the tween
Once it’s done with the tween it’d just call it again

1 Like

Didn’t knew that, looks like it’s unreliable.

Nah it’s just because it’s being ran in a while loop, I believe the implementation of a little ‘State’ thingy would work. (I sent it above)

1 Like

Oh yeah, that makes sense. It would play the tween every time it finishes so it looks like it looping the tween animation.

Yeah that’s exactly the problem. That’s why it’s probably best to (assuming we don’t wanna change the fact that it runs in a while loop) just compare the tween we want to play to the tween that was played last.

1 Like

while trying out your script I got this error Screenshot_232
leading me to that Screenshot_233

Oh I was worried about that, let me fix that really quick.

Replace that line with this:

				local Function = Callbacks[State] or function()end
				Function()

hey so while testing the billboard’s adornee is still nil but u can see it in the middle of the baseplate. Screenshot_234

and i noticed that Screenshot_235

and sorry for making you go through the pain of helping me fixing this small stuff I am just trying to improve my scripting.

Oh right. My bad.

local State,PreviousState = 0,0

local Callbacks = {
	[1] = function(seat) -- State 1
		Button.Button.Text = "F - Sit"
		Button.Adornee = seat
	end;
	[2] = function(seat)
		Button.Button.Text = ""
		Button.Adornee = nil
	end;
}

for i, v in pairs(workspace.SeatFolder:GetChildren())do
	spawn(function()
		while wait() do

			local WaitTime = 0;

			if v and (player.Character.PrimaryPart.Position - v.Position).Magnitude < distance then
				State = 1
			else
				State = 2
				WaitTime = .5
			end

			local TweenToPlay = State == 1 and tween or State == 2 and tween2
			if (PreviousState ~= State) then
				TweenToPlay:Play()
				wait(WaitTime)
				local Function = Callbacks[State] or function()end
				Function(v)
			end

			PreviousState = State
		end
	end)
end