@quenty/spring 2.2.0 → 3.0.1-canary.238.2c4d310.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +2 -37
- package/package.json +3 -3
- package/src/Shared/LinearValue.lua +52 -3
- package/src/Shared/Spring.lua +138 -51
- package/src/Shared/SpringUtils.lua +45 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [3.0.1-canary.238.2c4d310.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/spring@3.0.0...@quenty/spring@3.0.1-canary.238.2c4d310.0) (2021-12-29)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/spring
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [3.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/spring@2.2.0...@quenty/spring@3.0.0) (2021-12-22)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* Add spring support for UDim2 and UDim and Vector2 ([d1763d7](https://github.com/Quenty/NevermoreEngine/commit/d1763d7cdc65ad5df4bbe38897cd9a446bb61bb1))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
# [2.2.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/spring@2.1.0...@quenty/spring@2.2.0) (2021-12-18)
|
|
7
26
|
|
|
8
27
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
## Spring
|
|
2
2
|
<div align="center">
|
|
3
|
-
<a href="http://quenty.github.io/
|
|
3
|
+
<a href="http://quenty.github.io/NevermoreEngine/">
|
|
4
4
|
<img src="https://img.shields.io/badge/docs-website-green.svg" alt="Documentation" />
|
|
5
5
|
</a>
|
|
6
6
|
<a href="https://discord.gg/mhtGUS8">
|
|
7
|
-
<img src="https://img.shields.io/
|
|
7
|
+
<img src="https://img.shields.io/discord/385151591524597761?color=5865F2&label=discord&logo=discord&logoColor=white" alt="Discord" />
|
|
8
8
|
</a>
|
|
9
9
|
<a href="https://github.com/Quenty/NevermoreEngine/actions">
|
|
10
10
|
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/build.yml/badge.svg" alt="Build and release status" />
|
|
@@ -19,40 +19,5 @@ upon index making this model good for lazy applications
|
|
|
19
19
|
npm install @quenty/spring --save
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
## API
|
|
24
|
-
|
|
25
|
-
`Spring = Spring.new(number position)`
|
|
26
|
-
Creates a new spring in 1D
|
|
27
|
-
`Spring = Spring.new(Vector3 position)`
|
|
28
|
-
Creates a new spring in 3D
|
|
29
|
-
|
|
30
|
-
`Spring.Position`
|
|
31
|
-
Returns the current position
|
|
32
|
-
`Spring.Velocity`
|
|
33
|
-
Returns the current velocity
|
|
34
|
-
`Spring.Target`
|
|
35
|
-
Returns the target
|
|
36
|
-
`Spring.Damper`
|
|
37
|
-
Returns the damper
|
|
38
|
-
`Spring.Speed`
|
|
39
|
-
Returns the speed
|
|
40
|
-
|
|
41
|
-
`Spring.Target = number/Vector3`
|
|
42
|
-
Sets the target
|
|
43
|
-
`Spring.Position = number/Vector3`
|
|
44
|
-
Sets the position
|
|
45
|
-
`Spring.Velocity = number/Vector3`
|
|
46
|
-
Sets the velocity
|
|
47
|
-
`Spring.Damper = number [0, 1]`
|
|
48
|
-
Sets the spring damper, defaults to 1
|
|
49
|
-
`Spring.Speed = number [0, infinity)`
|
|
50
|
-
Sets the spring speed, defaults to 1
|
|
51
|
-
|
|
52
|
-
`Spring:TimeSkip(number DeltaTime)`
|
|
53
|
-
Instantly skips the spring forwards by that amount of now
|
|
54
|
-
`Spring:Impulse(number/Vector3 velocity)`
|
|
55
|
-
Impulses the spring, increasing velocity by the amount given
|
|
56
|
-
|
|
57
22
|
## Visualization
|
|
58
23
|
by Defaultio: https://www.desmos.com/calculator/hn2i9shxbz
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/spring",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1-canary.238.2c4d310.0",
|
|
4
4
|
"description": "Spring implementation for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@quenty/loader": "
|
|
32
|
+
"@quenty/loader": "3.1.2-canary.238.2c4d310.0"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "2c4d310b84afd0570d89667dc5d4aa69a0ef304a"
|
|
35
35
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
-- @author Quenty
|
|
1
|
+
--[=[
|
|
2
|
+
Represents a value that can operate in linear space
|
|
4
3
|
|
|
4
|
+
@class LinearValue
|
|
5
|
+
]=]
|
|
5
6
|
local LinearValue = {}
|
|
6
7
|
LinearValue.ClassName = "LinearValue"
|
|
7
8
|
LinearValue.__index = LinearValue
|
|
8
9
|
|
|
10
|
+
--[=[
|
|
11
|
+
Constructs a new LinearValue object.
|
|
12
|
+
|
|
13
|
+
@param constructor (number ...) -> T
|
|
14
|
+
@param values ({ number })
|
|
15
|
+
@return LinearValue<T>
|
|
16
|
+
]=]
|
|
9
17
|
function LinearValue.new(constructor, values)
|
|
10
18
|
return setmetatable({
|
|
11
19
|
_constructor = constructor;
|
|
@@ -13,10 +21,21 @@ function LinearValue.new(constructor, values)
|
|
|
13
21
|
}, LinearValue)
|
|
14
22
|
end
|
|
15
23
|
|
|
24
|
+
--[=[
|
|
25
|
+
Returns whether or not a value is a LinearValue object.
|
|
26
|
+
|
|
27
|
+
@param value any -- A value to check
|
|
28
|
+
@return boolean -- True if a linear value, false otherwise
|
|
29
|
+
]=]
|
|
16
30
|
function LinearValue.isLinear(value)
|
|
17
31
|
return type(value) == "table" and getmetatable(value) == LinearValue
|
|
18
32
|
end
|
|
19
33
|
|
|
34
|
+
--[=[
|
|
35
|
+
Converts the value back to the base value
|
|
36
|
+
|
|
37
|
+
@return T
|
|
38
|
+
]=]
|
|
20
39
|
function LinearValue:ToBaseValue()
|
|
21
40
|
return self._constructor(unpack(self._values))
|
|
22
41
|
end
|
|
@@ -57,6 +76,11 @@ local function operation(func)
|
|
|
57
76
|
end
|
|
58
77
|
end
|
|
59
78
|
|
|
79
|
+
--[=[
|
|
80
|
+
Returns the magnitude of the linear value.
|
|
81
|
+
|
|
82
|
+
@return number -- The magnitude of the linear value.
|
|
83
|
+
]=]
|
|
60
84
|
function LinearValue:GetMagnitude()
|
|
61
85
|
local dot = 0
|
|
62
86
|
for i=1, #self._values do
|
|
@@ -66,6 +90,13 @@ function LinearValue:GetMagnitude()
|
|
|
66
90
|
return math.sqrt(dot)
|
|
67
91
|
end
|
|
68
92
|
|
|
93
|
+
--[=[
|
|
94
|
+
Returns the magnitude of the linear value.
|
|
95
|
+
|
|
96
|
+
@prop magnitude number
|
|
97
|
+
@readonly
|
|
98
|
+
@within LinearValue
|
|
99
|
+
]=]
|
|
69
100
|
function LinearValue:__index(key)
|
|
70
101
|
if LinearValue[key] then
|
|
71
102
|
return LinearValue[key]
|
|
@@ -92,5 +123,23 @@ LinearValue.__div = operation(function(a, b)
|
|
|
92
123
|
return a / b
|
|
93
124
|
end)
|
|
94
125
|
|
|
126
|
+
function LinearValue:__eq(a, b)
|
|
127
|
+
if LinearValue.isLinear(a) and LinearValue.isLinear(b) then
|
|
128
|
+
if #a._values ~= #b._values then
|
|
129
|
+
return false
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
for i=1, #a._values do
|
|
133
|
+
if a._values[i] ~= b._values[i] then
|
|
134
|
+
return false
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
return true
|
|
139
|
+
else
|
|
140
|
+
return false
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
95
144
|
|
|
96
145
|
return LinearValue
|
package/src/Shared/Spring.lua
CHANGED
|
@@ -1,53 +1,51 @@
|
|
|
1
|
-
--[[
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Creates a new spring in 3D
|
|
13
|
-
|
|
14
|
-
Spring.Position
|
|
15
|
-
Returns the current position
|
|
16
|
-
Spring.Velocity
|
|
17
|
-
Returns the current velocity
|
|
18
|
-
Spring.Target
|
|
19
|
-
Returns the target
|
|
20
|
-
Spring.Damper
|
|
21
|
-
Returns the damper
|
|
22
|
-
Spring.Speed
|
|
23
|
-
Returns the speed
|
|
24
|
-
|
|
25
|
-
Spring.Target = number/Vector3
|
|
26
|
-
Sets the target
|
|
27
|
-
Spring.Position = number/Vector3
|
|
28
|
-
Sets the position
|
|
29
|
-
Spring.Velocity = number/Vector3
|
|
30
|
-
Sets the velocity
|
|
31
|
-
Spring.Damper = number [-infinity, infinity]
|
|
32
|
-
Sets the spring damper, defaults to 1
|
|
33
|
-
Spring.Speed = number [0, infinity)
|
|
34
|
-
Sets the spring speed, defaults to 1
|
|
35
|
-
|
|
36
|
-
Spring:TimeSkip(number DeltaTime)
|
|
37
|
-
Instantly skips the spring forwards by that amount of now
|
|
38
|
-
Spring:Impulse(number/Vector3 velocity)
|
|
39
|
-
Impulses the spring, increasing velocity by the amount given
|
|
40
|
-
|
|
41
|
-
Visualization (by Defaultio):
|
|
42
|
-
https://www.desmos.com/calculator/hn2i9shxbz
|
|
43
|
-
]]
|
|
1
|
+
--[=[
|
|
2
|
+
A physical model of a spring, useful in many applications.
|
|
3
|
+
|
|
4
|
+
A spring is an object that will compute based upon Hooke's law. Properties only evaluate
|
|
5
|
+
upon index making this model good for lazy applications.
|
|
6
|
+
|
|
7
|
+
```lua
|
|
8
|
+
local RunService = game:GetService("RunService")
|
|
9
|
+
local UserInputService = game:GetService("UserInputService")
|
|
10
|
+
|
|
11
|
+
local spring = Spring.new(Vector3.new(0, 0, 0))
|
|
44
12
|
|
|
13
|
+
RunService.RenderStepped:Connect(function()
|
|
14
|
+
if UserInputService:IsKeyDown(Enum.KeyCode.W) then
|
|
15
|
+
spring.Target = Vector3.new(0, 0, 1)
|
|
16
|
+
else
|
|
17
|
+
spring.Target = Vector3.new(0, 0, 0)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
print(spring.Position) -- A smoothed out version of the input keycode W
|
|
21
|
+
end)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A good visualization can be fond here, provided by Defaultio:
|
|
25
|
+
https://www.desmos.com/calculator/hn2i9shxbz
|
|
45
26
|
|
|
27
|
+
@class Spring
|
|
28
|
+
]=]
|
|
46
29
|
local Spring = {}
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
--[=[
|
|
32
|
+
Constructs a new Spring at the position and target specified, of type T.
|
|
33
|
+
|
|
34
|
+
```lua
|
|
35
|
+
-- Linear spring
|
|
36
|
+
local linearSpring = Spring.new(0)
|
|
37
|
+
|
|
38
|
+
-- Vector2 spring
|
|
39
|
+
local vector2Spring = Spring.new(Vector2.new(0, 0))
|
|
40
|
+
|
|
41
|
+
-- Vector3 spring
|
|
42
|
+
local vector3Spring = Spring.new(Vector3.new(0, 0, 0))
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
@param initial T -- The initial parameter is a number or Vector3 (anything with * number and addition/subtraction).
|
|
46
|
+
@param clock? () -> number -- The clock function is option, and is used to update the spring
|
|
47
|
+
@return Spring<T>
|
|
48
|
+
]=]
|
|
51
49
|
function Spring.new(initial, clock)
|
|
52
50
|
local target = initial or 0
|
|
53
51
|
clock = clock or os.clock
|
|
@@ -62,14 +60,22 @@ function Spring.new(initial, clock)
|
|
|
62
60
|
}, Spring)
|
|
63
61
|
end
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
--[=[
|
|
64
|
+
Impulses the spring, increasing velocity by the amount given. This is useful to make something shake,
|
|
65
|
+
like a Mac password box failing.
|
|
66
|
+
|
|
67
|
+
@param velocity T -- The velocity to impulse with
|
|
68
|
+
@return ()
|
|
69
|
+
]=]
|
|
67
70
|
function Spring:Impulse(velocity)
|
|
68
71
|
self.Velocity = self.Velocity + velocity
|
|
69
72
|
end
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
--[=[
|
|
75
|
+
Instantly skips the spring forwards by that amount time
|
|
76
|
+
@param delta number-- Time to skip forwards
|
|
77
|
+
@return ()
|
|
78
|
+
]=]
|
|
73
79
|
function Spring:TimeSkip(delta)
|
|
74
80
|
local now = self._clock()
|
|
75
81
|
local position, velocity = self:_positionVelocity(now+delta)
|
|
@@ -78,6 +84,87 @@ function Spring:TimeSkip(delta)
|
|
|
78
84
|
self._time0 = now
|
|
79
85
|
end
|
|
80
86
|
|
|
87
|
+
--[=[
|
|
88
|
+
The current position at the given clock time. Assigning the position will change the spring to have that position.
|
|
89
|
+
|
|
90
|
+
```lua
|
|
91
|
+
local spring = Spring.new(0)
|
|
92
|
+
print(spring.Position) --> 0
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
@prop Position T
|
|
96
|
+
@within Spring
|
|
97
|
+
]=]
|
|
98
|
+
--[=[
|
|
99
|
+
Alias for [Spring.Position](/api/Spring#Position)
|
|
100
|
+
|
|
101
|
+
@prop p T
|
|
102
|
+
@within Spring
|
|
103
|
+
]=]
|
|
104
|
+
--[=[
|
|
105
|
+
The current velocity. Assigning the velocity will change the spring to have that velocity.
|
|
106
|
+
|
|
107
|
+
```lua
|
|
108
|
+
local spring = Spring.new(0)
|
|
109
|
+
print(spring.Velocity) --> 0
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
@prop Velocity T
|
|
113
|
+
@within Spring
|
|
114
|
+
]=]
|
|
115
|
+
--[=[
|
|
116
|
+
Alias for [Spring.Velocity](/api/Spring#Velocity)
|
|
117
|
+
|
|
118
|
+
@prop v T
|
|
119
|
+
@within Spring
|
|
120
|
+
]=]
|
|
121
|
+
--[=[
|
|
122
|
+
The current target. Assigning the target will change the spring to have that target.
|
|
123
|
+
|
|
124
|
+
```lua
|
|
125
|
+
local spring = Spring.new(0)
|
|
126
|
+
print(spring.Target) --> 0
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
@prop Target T
|
|
130
|
+
@within Spring
|
|
131
|
+
]=]
|
|
132
|
+
--[=[
|
|
133
|
+
Alias for [Spring.Target](/api/Spring#Target)
|
|
134
|
+
@prop t T
|
|
135
|
+
@within Spring
|
|
136
|
+
]=]
|
|
137
|
+
--[=[
|
|
138
|
+
The current damper, defaults to 1. At 1 the spring is critically damped. At less than 1, it
|
|
139
|
+
will be underdamped, and thus, bounce, and at over 1, it will be critically damped.
|
|
140
|
+
|
|
141
|
+
@prop Damper number
|
|
142
|
+
@within Spring
|
|
143
|
+
]=]
|
|
144
|
+
--[=[
|
|
145
|
+
Alias for [Spring.Damper](/api/Spring#Damper)
|
|
146
|
+
|
|
147
|
+
@prop d number
|
|
148
|
+
@within Spring
|
|
149
|
+
]=]
|
|
150
|
+
--[=[
|
|
151
|
+
The speed, defaults to 1, but should be between [0, infinity)
|
|
152
|
+
|
|
153
|
+
@prop Speed number
|
|
154
|
+
@within Spring
|
|
155
|
+
]=]
|
|
156
|
+
--[=[
|
|
157
|
+
Alias for [Spring.Speed](/api/Spring#Speed)
|
|
158
|
+
|
|
159
|
+
@prop s number
|
|
160
|
+
@within Spring
|
|
161
|
+
]=]
|
|
162
|
+
--[=[
|
|
163
|
+
The current clock object to syncronize the spring against.
|
|
164
|
+
|
|
165
|
+
@prop Clock () -> number
|
|
166
|
+
@within Spring
|
|
167
|
+
]=]
|
|
81
168
|
function Spring:__index(index)
|
|
82
169
|
if Spring[index] then
|
|
83
170
|
return Spring[index]
|
|
@@ -181,4 +268,4 @@ function Spring:_positionVelocity(now)
|
|
|
181
268
|
b0*p0 + b1*p1 + b2*v0
|
|
182
269
|
end
|
|
183
270
|
|
|
184
|
-
return Spring
|
|
271
|
+
return Spring
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Utility functions that are related to the Spring object
|
|
3
|
+
@class SpringUtils
|
|
4
|
+
]=]
|
|
4
5
|
|
|
5
6
|
local EPSILON = 1e-6
|
|
6
7
|
|
|
@@ -9,6 +10,15 @@ local LinearValue = require("LinearValue")
|
|
|
9
10
|
|
|
10
11
|
local SpringUtils = {}
|
|
11
12
|
|
|
13
|
+
--[=[
|
|
14
|
+
Utility function that returns whether or not a spring is animating based upon
|
|
15
|
+
velocity and closeness to target, and as the second value, the value that should be
|
|
16
|
+
used.
|
|
17
|
+
|
|
18
|
+
@param spring Spring<T>
|
|
19
|
+
@param epsilon number? -- Optional epsilon
|
|
20
|
+
@return boolean, T
|
|
21
|
+
]=]
|
|
12
22
|
function SpringUtils.animating(spring, epsilon)
|
|
13
23
|
epsilon = epsilon or EPSILON
|
|
14
24
|
|
|
@@ -19,11 +29,14 @@ function SpringUtils.animating(spring, epsilon)
|
|
|
19
29
|
if type(target) == "number" then
|
|
20
30
|
animating = math.abs(spring.Position - spring.Target) > epsilon
|
|
21
31
|
or math.abs(spring.Velocity) > epsilon
|
|
22
|
-
elseif typeof(target) == "Vector3" or LinearValue.isLinear(target) then
|
|
23
|
-
animating = (spring.Position - spring.Target).magnitude > epsilon
|
|
24
|
-
or spring.Velocity.magnitude > epsilon
|
|
25
32
|
else
|
|
26
|
-
|
|
33
|
+
local rbxtype = typeof(target)
|
|
34
|
+
if rbxtype == "Vector3" or rbxtype == "Vector2" or LinearValue.isLinear(target) then
|
|
35
|
+
animating = (spring.Position - spring.Target).magnitude > epsilon
|
|
36
|
+
or spring.Velocity.magnitude > epsilon
|
|
37
|
+
else
|
|
38
|
+
error("Unknown type")
|
|
39
|
+
end
|
|
27
40
|
end
|
|
28
41
|
|
|
29
42
|
if animating then
|
|
@@ -34,7 +47,14 @@ function SpringUtils.animating(spring, epsilon)
|
|
|
34
47
|
end
|
|
35
48
|
end
|
|
36
49
|
|
|
37
|
-
--
|
|
50
|
+
--[=[
|
|
51
|
+
Add to spring position to adjust for velocity of target. May have to set clock to time().
|
|
52
|
+
|
|
53
|
+
@param velocity T
|
|
54
|
+
@param dampen number
|
|
55
|
+
@param speed number
|
|
56
|
+
@return T
|
|
57
|
+
]=]
|
|
38
58
|
function SpringUtils.getVelocityAdjustment(velocity, dampen, speed)
|
|
39
59
|
assert(velocity, "Bad velocity")
|
|
40
60
|
assert(dampen, "Bad dampen")
|
|
@@ -43,14 +63,31 @@ function SpringUtils.getVelocityAdjustment(velocity, dampen, speed)
|
|
|
43
63
|
return velocity*(2*dampen/speed)
|
|
44
64
|
end
|
|
45
65
|
|
|
66
|
+
--[=[
|
|
67
|
+
Converts an arbitrary value to a LinearValue if Roblox has not defined this value
|
|
68
|
+
for multiplication and addition.
|
|
69
|
+
|
|
70
|
+
@param value T
|
|
71
|
+
@return LinearValue<T> | T
|
|
72
|
+
]=]
|
|
46
73
|
function SpringUtils.toLinearIfNeeded(value)
|
|
47
74
|
if typeof(value) == "Color3" then
|
|
48
75
|
return LinearValue.new(Color3.new, {value.r, value.g, value.b})
|
|
76
|
+
elseif typeof(value) == "UDim2" then
|
|
77
|
+
return LinearValue.new(UDim2.new, {value.x.scale, value.x.offset, value.y.scale, value.y.offset})
|
|
78
|
+
elseif typeof(value) == "UDim" then
|
|
79
|
+
return LinearValue.new(UDim.new, {value.scale, value.offset})
|
|
49
80
|
else
|
|
50
81
|
return value
|
|
51
82
|
end
|
|
52
83
|
end
|
|
53
84
|
|
|
85
|
+
--[=[
|
|
86
|
+
Extracts the base value out of a packed linear value if needed.
|
|
87
|
+
|
|
88
|
+
@param value LinearValue<T> | any
|
|
89
|
+
@return T | any
|
|
90
|
+
]=]
|
|
54
91
|
function SpringUtils.fromLinearIfNeeded(value)
|
|
55
92
|
if LinearValue.isLinear(value) then
|
|
56
93
|
return value:ToBaseValue()
|