Allow for the joining of multiple Tweens into one

As a Roblox developer, it is currently too hard to play multiple tweens which you need to run in sync with eachother.

If Roblox is able to address this issue, it would improve my development experience because currently, doing this requires a lot of extra and inconvenient logic.

To demonstrate how I feel this would be useful, here is how you might use a feature like this:

-- Here is an example of how it might be useful:
local tween = someHowMergeTheseTweens({TweenService:Create(bullet, tweenInfo, bulletPropertyData), TweenService:Create(bulletTrail, tweenInfo, bulletTrailPropertyData})

tween:Play() -- Play all tweens
--tween:Cancel() -- Cancel all tweens
tween.Completed:Wait() -- All tweens will need to complete

bulletTrail.Enabled = false
bullet:Destroy()
7 Likes

This should be trivial to solve if you use the Promise pattern, e.g. by using this module: roblox-lua-promise | roblox-lua-promise

The solution to your issue is a ~20 line Lua module if you use the project above:


local Promise = require(...) -- path to roblox-lua-promise module

return function(tweens)
	return Promise.new(function(resolve, _, onCancel)
		local promises = {}

		for _, tween in ipairs(tweens) do
			table.insert(promises, Promise.fromEvent(tween.Completed))
			tween:Play()
		end

		Promise.all(promises):andThen(resolve)

		onCancel(function()
			for _, tween in ipairs(tweens) do
				tween:Cancel()
			end
		end)
	end)
end

Then use like so:

local TweenService = game:GetService("TweenService")

local playTweens = require(...) -- path to module defined above

-- Play all tweens:
local promise = playTweens {
   TweenService:Create(bullet, tweenInfo, bulletPropertyData),
   TweenService:Create(bulletTrail, tweenInfo, bulletTrailPropertyData)
}

-- promise:cancel() -- Cancel all tweens
promise:await() -- All tweens will need to complete

bulletTrail.Enabled = false
bullet:Destroy()

I don’t think there is enough to warrant turning this into an engine feature since this change would not actually enable any new use cases as far as I understand.

11 Likes

What about if I don’t want to use extra frameworks?

I feel that there is still argument to be made for something like this.

This is how I currently write out my tween code:

local tweenCompleted = Instance.new("BindableEvent")
local tweens = {TweenService:Create(...), TweenService:Create(...)}
local tweensDone = 0
local tweenCount = #tweens

local function checkTweens()
    tweensDone += 1
    if tweensDone >= tweenCount then
        tweenCompleted:Fire()
    end
end

tween1.Completed:Connect(checkTweens)
tween2.Completed:Connect(checkTweens)

for _, tween in ipairs(tweens) do
    tween:Play()
end

tweenCompleted.Event:Wait()

I find this to be quite messy, and I need a whole new loop every time I want to do something with those tweens, like cancel them. It feels very bulky, and it takes work to write for something where I am just doing four or five tweens together. Something I really like about TweenService is that is simplifies something that would generally be very messy to have in your code into something that’s only a couple lines, and something that takes hardly any time to do. You can do everything TweenService does in lua without too much effort but its extremely messy and it takes more skill to do.

Likewise I feel that my use case falls in the same boat.

If I am new to lua, assuming I’m still skilled enough to use tweens effectively, figuring out how to play more than a few tweens at once like this is not that trivial since, for example, my code above uses some code structures that aren’t as common, and I don’t think that finding extra framework code like what you supplied is something that most intermediate users will do. The type of code to look for requires that you have more knowledge about programming.

And like the code you supplied, tween modules existed before TweenService too, ones that I’ve used before. I think the difference is that these modules were much easier to find. And I think what made it worth it for TweenService was the size of these modules, and the complexity required for well made ones. Promises are not something that most intermediate Roblox users will know about but lerping and tweening are concepts that you’ll find pretty much everywhere because they’re a lot easier to understand.

I think that a feature like I’ve requested benefits me because its a lot easier for me to use but I also think that it benefits intermediate scripters a lot more than it would me.

2 Likes

Generally I agree with you, but the difference between TweenService and this feature is that TweenService has broad and frequent use cases, whereas merging tweens is not so much about tweening but more about trivial management of signals, which is a niche use case and not something that takes significant time or understanding to write a helper library for (or download a helper module for). It’s also not something every user is going to need, especially not those with little understanding about the underlying signals as you point out.

It’d be nice if Roblox provided some sort of Promise-like implementation as a built-in library. This is really generic and nice for an engine to provide. Merging tweens as a feature is too niche.

3 Likes

I think that merging tweens has more applications than you’d think. For example, let’s say I want to make a door styled after star wars, and my door has two pieces, a rotating piece in the center, and two sliding pieces. If I want the rotating piece to rotate in 2 seconds, and the door to open in 5, thus, two separate tween infos with two separate target properties, I have to merge them, there’s no easy way around it.

For your last statement, I do very much so agree with you, if Roblox provided a Promise-like implementation I think I’d be much happier since it means that users will be exposed to it, and I don’t have to be using extra framework code or anything. That would definitely fit my use case as well.

3 Likes