How to wait for previous tween to finish before playing another?

I’m trying to make a gradient do a full rotation using tweening whenever a button is pressed, and if the button is pressed again while the gradient is still rotating, it waits and doesn’t rotate a second time.

My issue is that the section with “print(“playback not finished yet”)” never runs, and I have no idea why.

I’ve tried a lot of other ways of achieving this, but none have worked, and the only possible solutions I can think of require writing way too much code then what should be necessary.

Here’s the specific code snippet from a bigger overall script:

local activetween = nil
local function rotateGradient(gradient)
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)
	activetween = gradtween
	if activetween.PlaybackState == Enum.PlaybackState.Playing then
		activetween.Completed:Wait()
		print("playback not finished yet")
	else
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
	end
end

local buttons = {
	Frame.Diagnostics.DiagnosisButton,
	Frame.Diagnostics.HousePowerButton,
	Frame.TopBar.DiagnosticsButton,
	Frame.TopBar.StoreButton
}

for _, button in ipairs(buttons) do
	button.MouseButton1Click:Connect(function()
		print("enter")
		rotateGradient(button.UIStroke.UIGradient)
	end)
end

Because you never play it
Vro :wilted_flower::skull_and_crossbones::skull_and_crossbones:

1 Like

Let me be more clear, the “activetween” is supposed to save the tween so when the function is called again, it can check if it’s still playing. I forgot to mention that the “activetween = gradtween” I moved to the bottom of the function so it’s not overridden, but it still didn’t work even then.

It looks like you’re setting your activetween to equal gradtween before checking if the tween is playing? I’d recommend adding logic to check if activetween exists prior to setting it equal to gradtween.

Or setting activetween to gradtween if you don’t have a tween playing.

I should read more

I think it should be something like this:

local activetween = nil
local function rotateGradient(gradient)
	if nil ~= activetween then return end
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	activetween = TweenService:Create(gradient, tweenInfoGradient, goal)
	activetween:Play()
	activetween.Completed:Wait()
	gradient.Rotation = 0
	activetween = nil
end
1 Like

Im so confused what is even the point of activetween?
You want it to be an upvalue or something


local function rotateGradient(button:TextButton):()
local UIGradient = button.UIStroke.UIGradient::UIGradient
local activetween:Tween?
	button.Activated:Connect(function()
local _activetween=activetween
		if _activetween then
		_activetween.Completed:Wait()
		print("playback not finished yet")
	else
		local currentRotation = UIGradient.Rotation
local goal = { Rotation = currentRotation + 180 }
local gradtween = TweenService:Create(UIGradient, tweenInfoGradient, goal)
activetween=gradtween
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
activetween=nil
	end
	end)
end


local temp = Frame.Diagnostics
rotateGradient(temp.DiagnosisButton)
rotateGradient(temp.HousePowerButton)
temp = Frame.TopBar
rotateGradient(temp.DiagnosticsButton)
rotateGradient(temp.StoreButton)

So basically what you’re saying is, you don’t want the tween to start again if there is already a tween playing?

I think you have it mostly correct but the thing is, You set the active tween variable (which I assume is a variable that contains a currently playing tween, if there is one) every time the functions runs and THEN check its state. Since you just set the active tween to a new one, the playback state will never be Playing.

So, it will create a tween, set the active tween to be that tween, checks if the active tween / gradtween is playing already, its not playing because it just got set to a new tween, so it plays the tween. I think this should be able to be fixed just with a simple change.

Here inside the rotateGradient function:

local function rotateGradient(gradient)
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)
	-- previous place where you were setting the active tween
	if activetween and activetween.PlaybackState == Enum.PlaybackState.Playing then
		activetween.Completed:Wait()
		print("playback not finished yet")
	else
        activetween = gradtween -- new location
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
	end
end

Basically what this does, instead it checks if the active tween is playing already before, if it is it will wait for it to finish and run your print statement.

If it doesn’t exist or isn’t playing, then it will play the tween and set the active tween.

That somewhat worked, as in it works when dealing with one button. However, for all the other buttons there’s a new issue, which is that if I click any other button, the rotation on the gradient doesn’t play for the other buttons. (I probably should’ve been more clear in my original post so let me be more specific)

Here’s a little image I made, basically I want it so that the border (that has a gradient) does a spin whenever clicked per button. It seems to work good for one button now, but clicking any of the others while one of the gradients on any of the buttons are still spinning makes it so they also don’t play.


(I hope this makes more sense)

Hmmmm, ok so from what I see you have it so the tween’s are all handled by one script for all of the buttons? Interesting.

Ok, so this might be a little bit complicated, but we are now going to change the system to use a table that keys the current button being pressed, and to check if the current buttons active tween is playing or not, so that it works with multiple.

So since you already pass through a unique Gradient value, we can use that. Here is the code:

local activetweens = {} -- it is now an empty table. Changed the name to add an s to the end, since it stores multiple now.
local function rotateGradient(gradient)
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)
	if activetweens[gradient] and activetweens[gradient].PlaybackState == Enum.PlaybackState.Playing then
		activetween.Completed:Wait()
		print("playback not finished yet")
	else
        activetweens[gradient] = gradtween
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
	end
end

local buttons = {
	Frame.Diagnostics.DiagnosisButton,
	Frame.Diagnostics.HousePowerButton,
	Frame.TopBar.DiagnosticsButton,
	Frame.TopBar.StoreButton
}

for _, button in ipairs(buttons) do
	button.MouseButton1Click:Connect(function()
		print("enter")
		rotateGradient(button.UIStroke.UIGradient)
	end)
end

This should work considering multiple buttons.

You can visualize the table being like {Frame.Diagnostics.DiagnosisButton.UIStroke.UIGradient = tween here} and basically since that key is different for every button, it can get different tweens / tween playback states depending on the button that was pressed.

1 Like

From what I am seeing, gradtween is a newly created tween. When you do: “if activetween.PlaybackState == Enum.PlaybackState.Playing then”, you are essentially checking if the newly created gradtween is playing. Which it won’t play because every time the function is called, a new tween gets created. I think what you should do is store the creation of the tween outside the function (not creating a new tween everytime you run the function)

Edit: My replies to this reply might be more helpful

or you could do this?

local function rotateGradient(gradient)
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)
	if activetween.PlaybackState == Enum.PlaybackState.Playing then
		activetween.Completed:Wait()
		print("playback not finished yet")
	else
        activetween = gradtween
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
	end
end

or this

local function rotateGradient(gradient)

	if activetween.PlaybackState == Enum.PlaybackState.Playing then
		activetween.Completed:Wait()
		print("playback not finished yet")
        return
    end

	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)

    activetween = gradtween

	gradtween:Play()
	gradtween.Completed:Wait()
	gradient.Rotation = 0
end

I can’t say I fully understand this (I’m still working on getting better at coding), but it DOES work, though I also get an error in the console, too for some reason.

image

Oh my bad, lemme fix that

local activetweens = {} -- it is now an empty table. Changed the name to add an s to the end, since it stores multiple now.
local function rotateGradient(gradient)
	local currentRotation = gradient.Rotation
	local goal = { Rotation = currentRotation + 180 }
	local gradtween = TweenService:Create(gradient, tweenInfoGradient, goal)
	if activetweens[gradient] and activetweens[gradient].PlaybackState == Enum.PlaybackState.Playing then
		activetweens[gradient].Completed:Wait() -- fixed line, forgot to update this
		print("playback not finished yet")
	else
        activetweens[gradient] = gradtween
		gradtween:Play()
		gradtween.Completed:Wait()
		gradient.Rotation = 0
	end
end

local buttons = {
	Frame.Diagnostics.DiagnosisButton,
	Frame.Diagnostics.HousePowerButton,
	Frame.TopBar.DiagnosticsButton,
	Frame.TopBar.StoreButton
}

for _, button in ipairs(buttons) do
	button.MouseButton1Click:Connect(function()
		print("enter")
		rotateGradient(button.UIStroke.UIGradient)
	end)
end

I forgot one line.

2 Likes

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