Fix springs not finishing when moving to zero (#98)

This commit is contained in:
Kaan 2026-10-19 14:05:23 +03:00 • committed by GitHub
parent b010497a01
commit 86dee3c87c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 2 deletions

View file

@ -10,6 +10,7 @@ local push_scope_as_child_of = graph.push_scope_as_child_of
local UPDATE_RATE = 120 local UPDATE_RATE = 120
local TOLERANCE_FACTOR = 10_000 local TOLERANCE_FACTOR = 10_000
local MIN_TOLERANCE = vector.create(1e-6, 1e-6, 1e-6)
type Animatable = number | CFrame | Color3 | UDim | UDim2 | Vector2 | Vector3 type Animatable = number | CFrame | Color3 | UDim | UDim2 | Vector2 | Vector3
@ -170,6 +171,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
local function updater_effect() local function updater_effect()
local value = source() local value = source()
data.x0_123, data.x0_456 = data.x_123, data.x_456
data.x1_123, data.x1_456 = type_to_vec6[typeof(value)](value) data.x1_123, data.x1_456 = type_to_vec6[typeof(value)](value)
data.source_value = value data.source_value = value
springs[data] = output springs[data] = output
@ -219,6 +221,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
-- set current position to value -- set current position to value
local v = ... :: T local v = ... :: T
data.x_123, data.x_456 = type_to_vec6[typeof(v)](v) data.x_123, data.x_456 = type_to_vec6[typeof(v)](v)
data.x0_123, data.x0_456 = data.x_123, data.x_456
-- reset velocity -- reset velocity
data.v_123 = vector.zero data.v_123 = vector.zero
@ -246,6 +249,12 @@ local function get_min_vector_step(direction: vector): vector
) )
end end
-- relative to the distance travelled, with a floor so springs can still settle at zero and large goals
local function get_tolerance(x0: vector, x1: vector): vector
local distance = vector.max(vector.abs(x0 - x1), vector.abs(x1))
return vector.max(get_min_vector_step(distance), MIN_TOLERANCE)
end
local function step_springs(dt: number) local function step_springs(dt: number)
for s in springs do for s in springs do
local k = s.k local k = s.k
@ -290,8 +299,8 @@ local function update_spring_sources()
local x1_123, x1_456 = data.x1_123, data.x1_456 local x1_123, x1_456 = data.x1_123, data.x1_456
local v_123, v_456 = data.v_123, data.v_456 local v_123, v_456 = data.v_123, data.v_456
local tol_123 = vector.abs(get_min_vector_step(x0_123 - x1_123)) local tol_123 = get_tolerance(x0_123, x1_123)
local tol_456 = vector.abs(get_min_vector_step(x0_456 - x1_456)) local tol_456 = get_tolerance(x0_456, x1_456)
if if
-- position is at goal (within tolerance) -- position is at goal (within tolerance)

View file

@ -2121,6 +2121,32 @@ TEST("spring()", wrap_root(function()
CHECK(count == 1) -- check spring was rescheduled correctly CHECK(count == 1) -- check spring was rescheduled correctly
end end
do CASE "spring finished at zero"
local input = source(1)
local output, control = spring(input)
local count = 0
effect(function()
output()
count += 1
end)
input(0)
step(10)
CHECK(output() == 0)
count = 0
step(1)
CHECK(count == 0) -- check spring is finished
control { impulse = 1 }
step(10)
count = 0
step(1)
CHECK(count == 0) -- check spring is finished after impulse at rest
end
do CASE "spring control" do CASE "spring control"
local input = source(1) local input = source(1)
local output, control = spring(input) local output, control = spring(input)