Epoxyish
Epoxyish is a generic solution to springing values unlike before. You can animate various data types and automatically have the springs animate to your instances based on values you create and change.
Everything is fully type-checked and thus should autofill.
Supported value types include:
- Number
- Vector2 & Vector2int16
- Vector3 & Vector3int16
- CFrame
- UDim
- UDim2
- Color3
The ideal format of expoyish is to store Spring, Value, and Latch as variables to speed up development process, and this post shows examples assuming such.
local Epoxyish = require(ReplicatedStorage.Epoxyish)
local Value = Epoxyish.Value
local Spring = Epoxyish.Spring
local Latch = Epoxyish.Latch
This resource uses the PascalCase name formatting for all value types, including variables, properties, and functions.
Expoxyish.Spring
Below is the type definition of a spring object:
export type SpringProperties = {
Speed : number?,
Dampening : number?,
Force : number?,
Mass : number?,
Target : {
Set : (any) -> nil,
Get : () -> any,
},
Position : any?,
Velocity : any?,
}
In other words, you can set speed, dampening, force, mass, position, velocity, and target. Required values are target, speed, and dampening.
Per your decision, you can change these values in runtime, including the data type of the target itself. For example, you can change the speed or force while the spring is calculating, and may even change the target from a number to a vector (if you have a use case for such).
Springs are object-oriented, so they should be treated similarly to Roblox instances programmatically. You can construct a spring like this, for example:
local ExampleSpring = Spring {
Target = MyValue,
Speed = 10,
Dampening = 5,
Mass = 8,
Force = 30,
Position = Color3.new(0, 1, 1),
}
Springs must have the target be a Expoxyish.Value
object, which is explained below. You can use them independently or with Epoxyish.Latch
.
If you want to detect when a spring is finished, you can do:
Spring.Completed:Connect(function()
...
end)
Springs sleep when they are completed. If a spring is at the target, the property Active
will be false. Otherwise, it will be true.
Spring objects also have three methods: Get
, Impulse
, and DisconnectLatch
.
Spring:Impulse(Force : any)
This method simply adds force to the current velocity of the spring. The force must match the data type of the target, otherwise, the position and velocity are reset.
Spring:Get(Property : string?)
This gets the current value of any index from the string. Property
defaults to Position
. For example, calling Spring:Get()
will get the current position of the spring, Spring:Get("Velocity")
gets the current velocity, etc.
The following values should not be read as properties and should instead be read through :Get()
to be accurate:
- Position
- Velocity
- Acceleration (not a property of spring anyways)
Spring:DisconnectLatch()
If you are using Latch
with the spring, calling this method disconnects the spring from it.
Springs do not actively calculate through RunService
, so they do not have any footprint until you read them.
Spring targets must be an
Epoxish.Value
type, no exceptions! Attempting to do otherwise will throw an error.
Epoxyish.Value
The Value
object is a simple instance that is constructed with any type of initial user data. The only two methods are :Set()
and :Get()
.
Below is an example using Value
:
local MyValue = Value(100)
print(MyValue:Get()) -- "100"
MyValue:Set(200)
print(MyValue:Get()) -- "200"
Epoxyish.Latch
This is the gold of this resource. Rather than having to use RunService
for reading and updating springs all of the time, you can just use Latch
. Latch supports many instance types, such as base parts, UI objects, value objects, etc. The only limitation is the actual property type.
Take a look at the code below using Latch
:
local PartPositionValue = Value(Target.Position)
local PartPositionSpring = Spring {
Target = PartPositionValue,
Speed = 5,
Dampening = 3,
}
Latch(Part) { -- Part is, well, a part.
Position = PartPositionSpring,
-- Index is the property name, value is ALWAYS a spring
}
Here is an example of changing the value to animate the spring:
while true do -- While loop is bad lmao
task.wait(1)
PartPositionValue:Set(Vector3.new(math.random(-30, 30), 10, math.random(-30, 30)))
end
The whole example script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Epoxyish = require(ReplicatedStorage.Epoxyish)
local Value = Epoxyish.Value
local Spring = Epoxyish.Spring
local Latch = Epoxyish.Latch
local Target = workspace.Target
local Part = workspace.Value
local PartPositionValue = Value(Target.Position)
local PartPositionSpring = Spring {
Target = PartPositionValue,
Speed = 5,
Dampening = 3,
}
Latch(Part) {
Position = PartPositionSpring
}
while true do
task.wait(1)
PartPositionValue:Set(Vector3.new(math.random(-30, 30), 10, math.random(-30, 30)))
end
And here is the result:
Again, notice how I never used RunService
to read the spring. It just works.
Get Epoxyish
Epoxyish is available on the Roblox Marketplace and Wally.
These resources take time and effort to make! Please support me for just $1 a month on my Patreon.
Shoutout to Eltobb, the formatting of the library is inspired by Fusion.