Tween to constantly make things fade into random colors

local Name, Collection, Tween, Info, Table = script.Name, game:GetService("CollectionService"), game:GetService("TweenService"), TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {}
local function Color(Part)
	local Task, Track = nil
	local function Resume()
		repeat
			Table.Color = BrickColor.Random().Color
			Track = Tween:Create(Part, Info, Table)
			Table.Color = nil
			Track:Play()
			task.wait(1)
		until nil
	end
	local function Check()
		if not Task and workspace:IsAncestorOf(Part) then Task = task.spawn(Resume) elseif Task then
			Track:Cancel()
			task.cancel(Task)
			Track, Task = nil
		end
	end
	Check() Part.AncestryChanged:Connect(Check)
end
Collection:GetInstanceAddedSignal(Name):Connect(Color)
for I, Tagged in ipairs(Collection:GetTagged(Name)) do
	Color(Tagged)
end

The idea here is to cancel the operation if the part leaves workspace and resume if the part re-enters workspace to avoid burning CPU on tweening parts that are not visible. But the method I came up with is quite complex. Is there a simpler way?

Edit: I have a newer version now:

local Name, Collection, Tween, Info, Active, Tmp = script.Name, game:GetService("CollectionService"), game:GetService("TweenService"), TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {}, {}
local function Color(Part)
	local Track: Tween?
	local function Try()
		Track[if workspace:IsAncestorOf(Part) then 'Play' else 'Pause'](Track)
	end
	local Signal = Part.AncestryChanged
	local Connect = Signal:Connect(Try)
	task.spawn(function()
		repeat
			Tmp.Color = BrickColor.Random().Color
			Track = Tween:Create(Part, Info, Tmp)
			Active[Part] = Track
			Tmp.Color = nil
			Track:Play()
		until Track.Completed:Wait() == Enum.PlaybackState.Cancelled
		Signal:Disconnect()
		Active[Part] = nil
	end)
	Try()
end
Collection:GetInstanceRemovedSignal(Name):Connect(function(Removed)
	local Track = Active[Removed]
	if not Track then return end
	Track:Cancel()
end)
Collection:GetInstanceAddedSignal(Name):Connect(Color)
for I, Tagged in ipairs(Collection:GetTagged(Name)) do
	Color(Tagged)
end

(workspace replaced for a folder to represent it works)

not sure if its a cleaner solution (its longer, but i think more readable) but an alternative approach anyways

local Name, Collection, Tween, Info, Active, Tmp = script.Name, game:GetService("CollectionService"), game:GetService("TweenService"), TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {}, {}

local disconnectFunctions = {}
function color(part)
	local tween
	local ancenstryChanged
	local coreLoop
	
	local function coreLoopFunc()
		return task.spawn(function()
			while true do
				if not tween then
					tween = Tween:Create(part, Info, {
						Color = BrickColor.Random().Color
					})
				end
				tween:Play()
				tween.Completed:Wait()
				tween = nil
			end
		end)
	end
	
	local function pauseTween()
		if tween then tween:Pause() end
		if coreLoop then task.cancel(coreLoop) end
	end
	
	local function playTween()
		coreLoop = coreLoopFunc()
	end
	
	local function onRemove()
		if tween then tween:Cancel() end
		if coreLoop then task.cancel(coreLoop) end
		if ancenstryChanged then ancenstryChanged:Disconnect() end
	end
	
	local function smartPlay()
		if workspace:IsAncestorOf(part) then
			playTween()
		else
			pauseTween()
		end
	end
	
	-- not sure if collections auto garbage collect that's why im assigning it to ancenstryChanged
	ancenstryChanged = part.AncestryChanged:Connect(smartPlay)
	
	smartPlay()
	
	return onRemove
end

function instanceAdded(part)
	local disconnectFunction = color(part)
	disconnectFunctions[part] = disconnectFunction
end

Collection:GetInstanceRemovedSignal(Name):Connect(function(part)
	local disconnectFunction = disconnectFunctions[part]
	if disconnectFunction then
		disconnectFunction()
		disconnectFunctions[part] = nil
	end
end)

for i, part in Collection:GetTagged(Name) do
	instanceAdded(part)
end

Collection:GetInstanceAddedSignal(Name):Connect(instanceAdded)
1 Like