As a ROBLOX developer, implementing tweening for non-instance values is not a beautiful process. Since TweenService doesn’t support non-instance values, I’m left with two options:
Write custom tweening framework
One of the reasons TweenService was created was to allow developers to use an existing library rather than writing their own. This is helpful because I don’t have to spend time making my own – writing my own tweening library defeats the purpose of TweenService. Writing my own tweening library also bloats distributed code and encourages developers to re-use code which may not follow best practices as opposed to an official service.
Hack TweenService to work with non-instance values
It’s possible to use ugily work around this by using dummy Value* instances that sync over Lua variables. Again, I’m encouraging other users to not follow best practices if I distribute something that they use as a learning resource. Even if I’m not making something that is meant to be distributed, hacking around TweenService in this way unnecessarily complicates my game.
Proxy values e.g. tween a percentage [0,1] that maps to a spritesheet and loads the ith of nth sprite
Internally tracked values e.g. plane wing health that is tracked by a script instead of a Humanoid
Mapping multiple instances to the same value e.g. setting a ship to full throttle would tween both the interface’s speed thrust meter and the physical thrust control handle
Alternative is to create two out-of-sync tweens or a dummy instance
Solves use case by allowing me to set individual properties on valueTween.Changed
Background tweening where I want a value to keep tweening but temporarily stop reflecting on an instance
Solves use case by allowing me to stop listening to valueTween.Changed while changes aren’t reflecting
If we could overload the instance argument of Create with a table of values, that would solve the above use cases:
I never really understood the aversion to using *Value instances by developers on this forum, how exactly is it hackish to tween a *Value instance? It seems like that was the intention of TweenService especially in conjunction with the Changed event of the *Value instances.
The only thing I can think of is unnecessary bloat in the game hierarchy, but this is resolvable by just having the *Value instance not have a parent in the game hierarchy, as its unnecessary (haven’t tested if TweenService requires instances to be descendants of game).
That it is designed to work with instances is a solution – not a problem. The original use case would have been something like “developers have to write their own tweening library for tweening values” . Assuming tweening non-Value* object variables is a reasonable use case, this fits right in with TweenService.
The question that matters is why I and the developers that liked the OP are not using Value* objects for tweening. Missing Value* objects certainly don’t help, but those aren’t the main reasons why I don’t use Value* objects for tweening. This is not discounting the use of Value* objects either (@Polymorphic) – only their use as a replacement for Lua variables.
Tweening dummy Value* objects obscure the intention of code
Barring services, most/all instances are intended to be used outside of the context that created them. A ScrollingFrame is meant to be used and viewed by the user in addition to the context that created it. A BodyMover is meant to affect the physics of objects to change the game world. All instances I’ve found have some overreaching impact and are not used exclusively for the context they were created in. Even Value* objects are used this way to provide user-friendly settings or a medium of communication between scripts.
By creating dummy Value objects for tweening, I’m not using them how instances are traditionally used. I’m using them in a non-standard way – a box that holds a value which is only accessible by the source context, the same as a Lua variable, instead of an instance that has an overreaching impact. It’s fine for Value* objects which are already being used (e.g. a lever which has a DoubleConstrainedValue “Angle”), but replacing Lua variables for the sake of TweenService compatibility is non-standard use.
There is no documentation or specification regarding instances that validates this statement, that I know of.
This seems like an idea you came up with based on observations on how you and others use instances. It would make sense if instances had limitations that prevented them from being used in incorrect ways. For example, “an instance works only when it is in the game tree”. But that is not the case; instances are functional in isolation, and there is no suggestion that they should not or must not be used that way. Just because a practice is uncommon doesn’t necessarily make it invalid.
You are absolutely correct. Don’t expect other developers to follow the practice though.
From our discussion this seems more opinionated than anything, and I don’t want to continue down that rabbit hole which doesn’t result in anything constructive/helpful. Regardless of which approach is “better”, we’re still going to see custom tweening libraries (e.g. Crazyman’s) from developers who don’t want to use Value* objects for tweening. Now that both angles have been made, I’ll leave it up to the ROBLOX engineers to decide what’s best for the platform.