mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Add spring setter
This commit is contained in:
parent
b44b9ef2ba
commit
3b22f6ccf9
4 changed files with 75 additions and 71 deletions
136
src/spring.luau
136
src/spring.luau
|
|
@ -1,23 +1,3 @@
|
|||
--[[
|
||||
|
||||
Supported datatypes:
|
||||
- number
|
||||
- CFrame
|
||||
- Color3
|
||||
- UDim
|
||||
- UDim2
|
||||
- Vector2
|
||||
- Vector3
|
||||
- Rect
|
||||
|
||||
Unsupported datatypes:
|
||||
- bool
|
||||
- Vector2int16
|
||||
- Vector3int16
|
||||
- EnumItem
|
||||
|
||||
]]
|
||||
|
||||
local throw = require "./throw"
|
||||
local graph = require "./graph"
|
||||
type Node<T> = graph.Node<T>
|
||||
|
|
@ -33,68 +13,68 @@ local UPDATE_RATE = 120
|
|||
local TOLERANCE = 0.001
|
||||
local TOLERANCE_VECTOR = vector.create(TOLERANCE, TOLERANCE, TOLERANCE)
|
||||
|
||||
type Vec3 = Vector3
|
||||
|
||||
local function Vec3(x: number, y: number, z: number): Vec3
|
||||
return vector.create(x, y, z)
|
||||
end
|
||||
|
||||
local ZERO = Vec3(0, 0, 0)
|
||||
|
||||
type Animatable = number | CFrame | Color3 | UDim | UDim2 | Vector2 | Vector3
|
||||
|
||||
type SpringData<T> = {
|
||||
--[[
|
||||
Unsupported datatypes:
|
||||
- bool
|
||||
- Vector2int16
|
||||
- Vector3int16
|
||||
- EnumItem
|
||||
]]
|
||||
|
||||
type SpringState<T> = {
|
||||
k: number, -- spring constant
|
||||
c: number, -- damping coeff
|
||||
|
||||
-- dimensions 1-3
|
||||
x0_123: Vec3,
|
||||
x1_123: Vec3,
|
||||
v_123: Vec3,
|
||||
|
||||
-- dimensions 4-6
|
||||
x0_456: Vec3,
|
||||
x1_456: Vec3,
|
||||
v_456: Vec3,
|
||||
x0_123: vector, x0_456: vector, -- current position
|
||||
x1_123: vector, x1_456: vector, -- target position
|
||||
v_123: vector, v_456: vector, -- current velocity
|
||||
|
||||
source_value: T -- current value of spring input source
|
||||
}
|
||||
|
||||
type TypeToVec6<T> = (T) -> (Vec3, Vec3)
|
||||
type Vec6ToType<T> = (Vec3, Vec3) -> T
|
||||
type SpringSettings<T> = ({
|
||||
position: T?,
|
||||
velocity: T?,
|
||||
impulse: T?
|
||||
}) -> ()
|
||||
|
||||
type TypeToVec6<T> = (T) -> (vector, vector)
|
||||
type Vec6ToType<T> = (vector, vector) -> T
|
||||
|
||||
local type_to_vec6 = {
|
||||
number = function(v)
|
||||
return Vec3(v, 0, 0), ZERO
|
||||
return vector.create(v, 0, 0), vector.zero
|
||||
end :: TypeToVec6<number>,
|
||||
|
||||
CFrame = function(v)
|
||||
return v.Position, Vec3(v:ToEulerAnglesXYZ())
|
||||
return v.Position, vector.create(v:ToEulerAnglesXYZ())
|
||||
end :: TypeToVec6<CFrame>,
|
||||
|
||||
Color3 = function(v)
|
||||
-- todo: hsv, oklab?
|
||||
return Vec3(v.R, v.G, v.B), ZERO
|
||||
return vector.create(v.R, v.G, v.B), vector.zero
|
||||
end :: TypeToVec6<Color3>,
|
||||
|
||||
UDim = function(v)
|
||||
return Vec3(v.Scale, v.Offset, 0), ZERO
|
||||
return vector.create(v.Scale, v.Offset, 0), vector.zero
|
||||
end :: TypeToVec6<UDim>,
|
||||
|
||||
UDim2 = function(v)
|
||||
return Vec3(v.X.Scale, v.X.Offset, v.Y.Scale), Vec3(v.Y.Offset, 0, 0)
|
||||
return vector.create(v.X.Scale, v.X.Offset, v.Y.Scale), vector.create(v.Y.Offset, 0, 0)
|
||||
end :: TypeToVec6<UDim2>,
|
||||
|
||||
Vector2 = function(v)
|
||||
return Vec3(v.X, v.Y, 0), ZERO
|
||||
return vector.create(v.X, v.Y, 0), vector.zero
|
||||
end :: TypeToVec6<Vector2>,
|
||||
|
||||
Vector3 = function(v)
|
||||
return v, ZERO
|
||||
return v, vector.zero
|
||||
end :: TypeToVec6<Vector3>,
|
||||
|
||||
Rect = function(v)
|
||||
return Vec3(v.Min.X, v.Min.Y, v.Max.X), Vec3(v.Max.Y, 0, 0)
|
||||
return vector.create(v.Min.X, v.Min.Y, v.Max.X), vector.create(v.Max.Y, 0, 0)
|
||||
end :: TypeToVec6<Rect>
|
||||
}
|
||||
|
||||
|
|
@ -143,10 +123,10 @@ setmetatable(vec6_to_type, invalid_type)
|
|||
|
||||
-- maps spring data to its corresponding output node
|
||||
-- lifetime of spring data is tied to output node
|
||||
local springs: { [SpringData<any>]: SourceNode<any> } = {}
|
||||
setmetatable(springs, { __mode = "v" })
|
||||
local springs: { [SpringState<unknown>]: SourceNode<unknown> } = {}
|
||||
setmetatable(springs :: any, { __mode = "v" })
|
||||
|
||||
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): () -> T
|
||||
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): (() -> T, SpringSettings<T>)
|
||||
local owner = assert_stable_scope()
|
||||
|
||||
-- https://en.wikipedia.org/wiki/Damping
|
||||
|
|
@ -164,17 +144,17 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
throw("spring damping too high, consider reducing damping or increasing period")
|
||||
end
|
||||
|
||||
local data: SpringData<T> = {
|
||||
local data: SpringState<T> = {
|
||||
k = k,
|
||||
c = c,
|
||||
|
||||
x0_123 = ZERO,
|
||||
x1_123 = ZERO,
|
||||
v_123 = ZERO,
|
||||
x0_123 = vector.zero,
|
||||
x1_123 = vector.zero,
|
||||
v_123 = vector.zero,
|
||||
|
||||
x0_456 = ZERO,
|
||||
x1_456 = ZERO,
|
||||
v_456 = ZERO,
|
||||
x0_456 = vector.zero,
|
||||
x1_456 = vector.zero,
|
||||
v_456 = vector.zero,
|
||||
|
||||
source_value = false :: any,
|
||||
}
|
||||
|
|
@ -185,7 +165,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
local value = source()
|
||||
data.x1_123, data.x1_456 = type_to_vec6[typeof(value)](value)
|
||||
data.source_value = value
|
||||
springs[data] = output -- todo: investigate why insertion is not O(1) at ~20k springs
|
||||
springs[data] = output
|
||||
return value
|
||||
end
|
||||
|
||||
|
|
@ -199,6 +179,28 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
-- set output to goal
|
||||
output.cache = data.source_value
|
||||
|
||||
local setter = function(p)
|
||||
local x = p.position
|
||||
local v = p.velocity
|
||||
local dv = p.impulse
|
||||
|
||||
if x then
|
||||
data.x0_123, data.x0_456 = type_to_vec6[typeof(x)](x)
|
||||
end
|
||||
|
||||
if v then
|
||||
data.v_123, data.v_456 = type_to_vec6[typeof(v)](v)
|
||||
end
|
||||
|
||||
if dv then
|
||||
local dv_123, dv_456 = type_to_vec6[typeof(dv)](dv)
|
||||
data.v_123 += dv_123
|
||||
data.v_456 += dv_456
|
||||
end
|
||||
|
||||
springs[data] = output
|
||||
end :: SpringSettings<T>
|
||||
|
||||
return function(...)
|
||||
if select("#", ...) == 0 then -- no args were given
|
||||
push_child_to_scope(output)
|
||||
|
|
@ -210,8 +212,8 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
data.x0_123, data.x0_456 = type_to_vec6[typeof(v)](v)
|
||||
|
||||
-- reset velocity
|
||||
data.v_123 = ZERO
|
||||
data.v_456 = ZERO
|
||||
data.v_123 = vector.zero
|
||||
data.v_456 = vector.zero
|
||||
|
||||
-- schedule spring
|
||||
springs[data] = output
|
||||
|
|
@ -220,7 +222,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
output.cache = v
|
||||
|
||||
return v
|
||||
end
|
||||
end, setter
|
||||
end
|
||||
|
||||
local function step_springs(dt: number)
|
||||
|
|
@ -264,7 +266,7 @@ end
|
|||
local remove_queue = {}
|
||||
|
||||
local function update_spring_sources()
|
||||
for data, output in next, springs do
|
||||
for data, output in springs do
|
||||
local x0_123, x1_123, v_123,
|
||||
x0_456, x1_456, v_456 =
|
||||
data.x0_123, data.x1_123, data.v_123,
|
||||
|
|
@ -280,7 +282,7 @@ local function update_spring_sources()
|
|||
|
||||
if max_difference == TOLERANCE_VECTOR then
|
||||
-- close enough to target, unshedule spring and set value to target
|
||||
table.insert(remove_queue, data)
|
||||
springs[data] = nil
|
||||
output.cache = data.source_value
|
||||
else
|
||||
output.cache = vec6_to_type[typeof(data.source_value)](x0_123, x0_456)
|
||||
|
|
@ -288,12 +290,6 @@ local function update_spring_sources()
|
|||
|
||||
update_descendants(output)
|
||||
end
|
||||
|
||||
for _, data in next, remove_queue do
|
||||
springs[data] = nil
|
||||
end
|
||||
|
||||
table.clear(remove_queue)
|
||||
end
|
||||
|
||||
return function()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue