Repeat tween on parts but not on the same unless its finished

Hello, I’m trying to make this script work for each part as shown in the video, however only one seems to trigger and then after the tween is finished i am able to trigger another, I want to trigger as many as I can but not trigger the same that already was tweening ( not fun results ), how could I go around this?

Video:
https://i.gyazo.com/8ee49603af0250f45c0d4f76b32f4bd6.mp4

Script:

local Players = game:GetService("Players")
local debounce = false

local function onCharacterAdded(char)

	local hum = char:WaitForChild("Humanoid")
	local torso = char:WaitForChild("Torso")
	local wtb = char:WaitForChild("WantsToBuild")
	local legL = char:WaitForChild('Left Leg')
	local legR = char:WaitForChild('Right Leg')


	if hum then
		hum.Changed:Connect(function()
			if hum.FloorMaterial == Enum.Material.Sand and wtb.Value == true then
				local myray = Ray.new(torso.Position, Vector3.new(0,-10,0))

				local hit, position = game.Workspace:FindPartOnRayWithIgnoreList(myray, {hum, legR, legL})

				if hit.Name == 'Snow' then
					if debounce then return end
					debounce = true
					print(hit.Name..' was hit')

					local tween = game:GetService('TweenService')

					local info = TweenInfo.new(
						5,           --seconds it takes to complete loop
						Enum.EasingStyle.Linear,     --easingstyle (how it moves)
						Enum.EasingDirection.InOut,    --easingdirection (which direction)
						0,                    --times repeated (negative number if u want infinite)
						true,                 --reverse (does it go back to its spot)
						0                      --delay time (stoptime before doing the tween)
					)

					local Goals = {             --YOU CAN CHANGE THESE AND DELETE THE THINGS YOU DON'T WANT TO TWEEN
						Transparency = 1,
						Position = Vector3.new(hit.Position.X, hit.Position.Y -2.5, hit.Position.Z)

					}

					local start = tween:Create(hit, info, Goals) --gets all the info and goals and creates tween

					start:Play()
					start.Completed:Wait()
					print('done')
					debounce = false

				else

					-- print('air')
				end

			end
		end)
	end
end



	local function onPlayerAdded(player)
		player.CharacterAdded:Connect(onCharacterAdded)
	end

	Players.PlayerAdded:Connect(onPlayerAdded)

I’m sure you’re already aware of this, but the reason you can only trigger one at a time is because of the nature of your debounce approach- it can only account for one individual snow part at a time.

I suggest you take a dynamic debounce approach. Essentially, you utilize a table that stores all of the snow parts that have been recently touched. At the beginning, your table should be empty and declared at the top of the script. When a snow part is touched, check to see if the given part already exists in the table. If it doesn’t (meaning it hasn’t been touched recently) add it to the table. This is the equivalent of making sure the variable debounce is false and setting it to true in a linear debounce approach. Then, once you’re ready to allow the snow part to be animated again, simply remove the snow part from the table.

The following code demonstrates this concept; however, I am not in the position to make sure it’s 100% working so I preemptively apologize for any errors. I have basically just replaced your linear debounce method with my dynamic debounce method and left comments explaining what each line does.

local Players = game:GetService("Players")
local snowsToIgnore = {} --Table to store snow parts

local function onCharacterAdded(char)

	local hum = char:WaitForChild("Humanoid")
	local torso = char:WaitForChild("Torso")
	local wtb = char:WaitForChild("WantsToBuild")
	local legL = char:WaitForChild('Left Leg')
	local legR = char:WaitForChild('Right Leg')


	if hum then
		hum.Changed:Connect(function()
			if hum.FloorMaterial == Enum.Material.Sand and wtb.Value == true then
				local myray = Ray.new(torso.Position, Vector3.new(0,-10,0))

				local hit, position = game.Workspace:FindPartOnRayWithIgnoreList(myray, {hum, legR, legL})

				if hit.Name == 'Snow' then
					if table.find(snowsToIgnore, hit) then return end --Returns nothing if the given snow part already exists in the table (meaning it's been touched recently)
					table.insert(snowsToIgnore, hit) --Since the snow part hasn't been touched recently, add it to the table 
					print(hit.Name..' was hit')

					local tween = game:GetService('TweenService')

					local info = TweenInfo.new(
						5,           --seconds it takes to complete loop
						Enum.EasingStyle.Linear,     --easingstyle (how it moves)
						Enum.EasingDirection.InOut,    --easingdirection (which direction)
						0,                    --times repeated (negative number if u want infinite)
						true,                 --reverse (does it go back to its spot)
						0                      --delay time (stoptime before doing the tween)
					)

					local Goals = {             --YOU CAN CHANGE THESE AND DELETE THE THINGS YOU DON'T WANT TO TWEEN
						Transparency = 1,
						Position = Vector3.new(hit.Position.X, hit.Position.Y -2.5, hit.Position.Z)

					}

					local start = tween:Create(hit, info, Goals) --gets all the info and goals and creates tween

					start:Play()
					start.Completed:Wait()
					print('done')
					table.remove(snowsToIgnore, table.find(snowsToIgnore, hit)) --Remove the snow part from the table
				else

					-- print('air')
				end

			end
		end)
	end
end



local function onPlayerAdded(player)
	player.CharacterAdded:Connect(onCharacterAdded)
end

Players.PlayerAdded:Connect(onPlayerAdded)

Hopefully this helps. Let me know if you have any issues or further questions.

1 Like

You could use coroutines/task.spawn() to create multiple threads to handle the creation and playing of each tween. Since currently the thread is yielded due to “Wait()” until the completed event fires for the created tween before continuing on with the next iteration of the loop.

task.spawn() approach:

task.spawn(function()
	start:Play()
	start.Completed:Wait()
	print('done')
	debounce = false
end)

coroutines approach:

coroutine.resume(coroutine.create(function()
	start:Play()
	start.Completed:Wait()
	print('done')
	debounce = false
end)

and:

coroutine.wrap(function()
	start:Play()
	start.Completed:Wait()
	print('done')
	debounce = false
end)()

You may need a unique debounce for each tween (which you could implement through the creation of a table).

1 Like