Tweens Do Not Play Together?

  1. What do you want to achieve? Keep it simple and clear!
    I want to add tweens to a table so that I can then play them at the same time. These tweens do not play on the same parts. I want to do this because I want to press a gui button that plays the two tweens on two different groups of parts that I grouped with a tag property.

  2. What is the issue? Include screenshots / videos if possible!
    The issue is that when I add the tweens to the table, only the second tween plays.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    What I have tried is to remove the [1] from tweens[1]:Play and only do tweens:Play() but that does not play either tween and I get the error “attempt to call missing method ‘Play’ of table.”

I do want to add that if i add a wait between the two tweens as I add them to the table, it works! But I don’t want to have a big wait between the tweens running. I want them to play at the same time.

Here is the original script and video of how it looks.

local TweenService = game:GetService("TweenService")
local CollectionService = game:GetService("CollectionService")
local Module = require(script.ModuleScript)
local Button = Module.Buttons
local Bulbs = Module.Bulbs
local LEDs = Module.LEDs
local TweenInfo = Module.Tween
local Color = Module.Colors

local tweens = {}
local tweensRunning = false

function runTween()
	tweensRunning = true
	tweens[1]:Play()
	warn("TWEEN SUCCESSFUL")
	table.remove(tweens, 1)
	if #tweens > 0 then
		runTween()
	else
		tweensRunning = false
	end
end

function addTween(tweenToAdd)
	table.insert(tweens, tweenToAdd)
	if not tweensRunning then
		task.spawn(runTween)
	end
end

local function BulbTweens(tagIndex, initialColorValue, finalColorValue)
	for _, Lights in pairs(CollectionService:GetTagged(Bulbs[tagIndex])) do
		local initialColor = TweenService:Create(Lights, TweenInfo[1], initialColorValue)
		local finalColor = TweenService:Create(Lights, TweenInfo[2], finalColorValue)
		Button[1].MouseButton1Click:Connect(function()
			addTween(initialColor)
			print("INITIAL TWEEN IN TABLE")
			addTween(finalColor)
			print("FINAL TWEEN IN TABLE")
		end)
	end
end

BulbTweens(1, Color[21], Color[25])
BulbTweens(2, Color[25], Color[21])

Now here I will use the same script except I add a wait(5) at line 39 between addTween(initialColor) and addTween(finalColor)

So I know a solution, I just want to know if there is a better one or if there is a different way to achieve the same result differently? Any suggestions are welcome, thank you!

2 Likes

If the desired functionality will always be to:

  1. Create multiple Tweens at once upon pressing the button
  2. Immediately afterwards, play all of them at the same time

You could adjust the way that the runTween function is called so that it only begins playing the Tweens once everything has been added to the tweens table:

Example revision

local tweens = {}
local tweensRunning = false

function runTween()
    tweensRunning = true

    for index, existingTween in tweens do
        existingTween:Play()
	    warn("TWEEN #"..index.." SUCCESSFUL")
    end

    table.clear(tweens)
--[[
If you want to wait to set tweensRunning to false until all of the Tweens
have finished playing, you could make use of tween.Completed on each of the
Tweens so that you know when each one finishes playing (although there would
need to be a few extra changes to make that possible without also preventing
the other Tweens from playing at the same time)
--]]
    tweensRunning = false
end

function addTween(tweenToAdd)
--[[ If you don't want new Tweens to be added to the table when some are
already playing (so that if someone presses the red button to play
that sequence, that they must wait until it's done playing until they
can press any of the other buttons), you could add the `if not tweensRunning`
check before adding anything to the tweens table.
--]]
	table.insert(tweens, tweenToAdd)
	--if not tweensRunning then
		--task.spawn(runTween)
	--end
end

local function BulbTweens(tagIndex, initialColorValue, finalColorValue)
	for _, Lights in pairs(CollectionService:GetTagged(Bulbs[tagIndex])) do
		local initialColor = TweenService:Create(Lights, TweenInfo[1], initialColorValue)
		local finalColor = TweenService:Create(Lights, TweenInfo[2], finalColorValue)
		Button[1].MouseButton1Click:Connect(function()
			addTween(initialColor)
			print("INITIAL TWEEN IN TABLE")
			addTween(finalColor)
			print("FINAL TWEEN IN TABLE")

-- Calling the function to run the tweens since we know both have been added
            runTween()
		end)
	end
end

BulbTweens(1, Color[21], Color[25])
BulbTweens(2, Color[25], Color[21])
3 Likes

Thank you! So I tried this and I still ended up with the first tween playing but the second one doesn’t. If I put a wait time between addTween(initialColor) and addTween(finalColor) of atleast one second then it runs how I want to just like in the second video I showed. :frowning_face:

Also this is what the output looks like, it only says tween #1 was successful and not tween 2.

image

(btw I’ve been subbed to your youtube and seen some of your videos, you’ve helped me out sm before! :grin:)

2 Likes

Hmmm, that’s odd; it’s interesting that it’s still adding the tween to the table and then immediately playing it, since the revised BulbTweens function waits to call runTween() until after the Tweens for the initialColor and finalColor are added to the table.

Make sure that this conditional statement from the addTween table was temporarily commented out, since that could be interfering with the revised version:


local function BulbTweens(tagIndex, initialColorValue, finalColorValue)
	for _, Lights in pairs(CollectionService:GetTagged(Bulbs[tagIndex])) do
		local initialColor = TweenService:Create(Lights, TweenInfo[1], initialColorValue)
		local finalColor = TweenService:Create(Lights, TweenInfo[2], finalColorValue)
		Button[1].MouseButton1Click:Connect(function()

...


BulbTweens(1, Color[21], Color[25])
BulbTweens(2, Color[25], Color[21])

If you don’t mind, could you provide some additional context about how this is structured (especially the Bulbs[tagIndex], Button[1], etc.)? I think I get the gist of what everything is referring to, but knowing more about that might make it easier to understand how everything is working together.

Along with that, what does the script look like now after making those revisions earlier? Would be good to be able to reference that to make sure we’re on the same page.


I’m about to go eat so I won’t respond for a while, but I’ll continue thinking about possible solutions.

I’m glad that the tutorials have been useful for you; thank you so much! :smile: I haven’t uploaded a new tutorial in a very long time but I hope to start creating new videos again very soon.

And hopefully I won’t disappoint by not being able to figure out a solution to this, haha

2 Likes

After messaging back and forth with @AneTChrist, we found a solution! Here’s the explanation I offered:


I think I’ve figured out what’s happening! First, I’ll explain a bit about the original implementation you used, I’ll discuss what went wrong with my example revision, and then I’ll detail what I’ve found after running some tests and provide a possible solution.


The reason that the added delay (which was mentioned in the original post from your thread) helped achieve the intended effect was because it gave enough time for the initialColor Tween to fully complete before the finalColor Tween started.

When it doesn’t have enough time to complete the initial Tween, the second one essentially overrides it from where it left off and then begins the infinite back-and-forth loop between the color it was at that moment and the finalColor. That’s the fundamental issue that also led to the unintended behavior from my example revision, as my revision was activating the Tweens back-to-back.

(@AneTChrist had posted another example video that utilized the changes from my example revision; I quoted that in this spot of the message)

Funnily enough, I was able to replicate the issue shown in the video by slightly modifying the TweenService code I wrote for some sliding doors in a testing place from a few years ago. I updated its Color instead of CFrame and ran two scenarios that roughly matches what was tried in the original post:

  1. Playing the open Tween (which is equivalent to initialColor) and then immediately playing the close Tween (which is equivalent to finalColor).

  2. The same thing as the first scenario, except there is a 5-second wait between the opening and closing Tweens

For reference, the starting color of the doors is red, with the open Tween turning it to green, and the close Tween turning it to blue.

In the first scenario, it basically never plays the open Tween, as it only alternates between the starting color of red and the closing color of blue.

In the second scenario (with the 5-second wait), the open Tween has enough time to finish and turn the door green, so that by the time the close Tween starts, it’ll repeatedly alternate between the color it was at the moment and the goal color defined for the close Tween (which was blue).


This means that the script pretty much just need to be confident in the fact that the initialColor Tween has completed before starting the finalColor Tween. However, at the same time, it also needs to be structured in a way where it will check this for every single lightbulb at the same time as to avoid desynchronization issues.

With that in mind, here’s another example revision which should bring it a step closer to that, but no guarantees that it’ll be 100% quite yet!

local TweenService = game:GetService("TweenService")
local CollectionService = game:GetService("CollectionService")
local Module = require(script.ModuleScript)
local Button = Module.Buttons
local Bulbs = Module.Bulbs
local LEDs = Module.LEDs
local TweenInfo = Module.Tween
local Color = Module.Colors


local function runTween(tweens)
	local initialColorTween = tweens[1]
	local finalColorTween = tweens[2]

	initialColorTween:Play()
	warn("initialColor TWEEN SUCCESSFUL")
	initialColorTween.Completed:Wait()
	
	finalColorTween:Play()
	warn("finalColor TWEEN SUCCESSFUL")
	
	table.clear(tweens)
	tweens = nil
end

local function addTween(tweensToAdd)
	local tweens = {}
	
	for _, tween in tweensToAdd do
		table.insert(tweens, tween)
	end
	
	return tweens
end

local function BulbTweens(tagIndex, initialColorValue, finalColorValue)
	for _, Lights in pairs(CollectionService:GetTagged(Bulbs[tagIndex])) do
		
		local initialColor = TweenService:Create(Lights, TweenInfo[1], initialColorValue)
		local finalColor = TweenService:Create(Lights, TweenInfo[2], finalColorValue)
		
		Button[1].MouseButton1Click:Connect(function()
			local tweens = addTween({initialColor, finalColor})
			print("BOTH TWEENS IN TABLE")
			task.spawn(runTween, tweens)
		end)
		
	end
end

BulbTweens(1, Color[24], Color[5])
BulbTweens(2, Color[24], Color[5])

After that explanation, the last things that were done included the following:

  • Continued using two separate TweenInfos, one for the initialColor Tween and another for the finalColor Tween.

  • @AneTChrist updated the TweenInfo for the initialColor Tween to have the number of repeats set to 0 (and kept whether or not it reversed set to false).

  • And also kept the TweenInfo for the finalColor the same, having the number of repeats set to -1 (so it goes forever) and whether or not it reversed set to true.

From there, it ended up working as intended!

2 Likes