roblox-opencode 1.0.0 → 1.0.1
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/README.md +112 -122
- package/commands/setup-game.md +108 -108
- package/commands/sync-check.md +53 -53
- package/core/roblox-core.md +93 -93
- package/dist/server.js +189 -167
- package/package.json +35 -35
- package/skills/roblox-analytics/SKILL.md +277 -277
- package/skills/roblox-analytics/references/event-batcher.luau +75 -75
- package/skills/roblox-animation-vfx/SKILL.md +1325 -1325
- package/skills/roblox-architecture/SKILL.md +863 -863
- package/skills/roblox-architecture/references/combat-systems.md +1381 -1381
- package/skills/roblox-code-review/SKILL.md +686 -686
- package/skills/roblox-data/SKILL.md +889 -889
- package/skills/roblox-data/references/inventory-systems.md +1729 -1729
- package/skills/roblox-debug/SKILL.md +98 -98
- package/skills/roblox-gui/SKILL.md +1103 -1103
- package/skills/roblox-gui-fusion/SKILL.md +150 -150
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -427
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -579
- package/skills/roblox-gui-fusion/references/shop.luau +411 -411
- package/skills/roblox-luau-mastery/SKILL.md +1519 -1519
- package/skills/roblox-monetization/SKILL.md +1084 -1084
- package/skills/roblox-monetization/references/process-receipt.luau +131 -131
- package/skills/roblox-networking/SKILL.md +669 -669
- package/skills/roblox-networking/references/remote-validator.luau +193 -193
- package/skills/roblox-publish-checklist/SKILL.md +127 -127
- package/skills/roblox-runtime/SKILL.md +753 -753
- package/skills/roblox-sharp-edges/SKILL.md +294 -294
- package/skills/roblox-sync/SKILL.md +126 -126
- package/skills/roblox-testing/SKILL.md +943 -943
- package/skills/roblox-tooling/SKILL.md +149 -149
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -201
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -7
- package/vendor/LICENSES/promise-LICENSE +20 -20
- package/vendor/LICENSES/t-LICENSE +21 -21
- package/vendor/LICENSES/testez-LICENSE +200 -200
- package/vendor/README.md +83 -83
- package/vendor/fusion/Animation/ExternalTime.luau +83 -83
- package/vendor/fusion/Animation/Spring.luau +321 -321
- package/vendor/fusion/Animation/Stopwatch.luau +127 -127
- package/vendor/fusion/Animation/Tween.luau +187 -187
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -27
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -47
- package/vendor/fusion/Animation/lerpType.luau +163 -163
- package/vendor/fusion/Animation/packType.luau +99 -99
- package/vendor/fusion/Animation/springCoefficients.luau +80 -80
- package/vendor/fusion/Animation/unpackType.luau +102 -102
- package/vendor/fusion/Colour/Oklab.luau +70 -70
- package/vendor/fusion/Colour/sRGB.luau +54 -54
- package/vendor/fusion/External.luau +167 -167
- package/vendor/fusion/ExternalDebug.luau +69 -69
- package/vendor/fusion/Graph/Observer.luau +113 -113
- package/vendor/fusion/Graph/castToGraph.luau +28 -28
- package/vendor/fusion/Graph/change.luau +80 -80
- package/vendor/fusion/Graph/depend.luau +32 -32
- package/vendor/fusion/Graph/evaluate.luau +55 -55
- package/vendor/fusion/Instances/Attribute.luau +57 -57
- package/vendor/fusion/Instances/AttributeChange.luau +46 -46
- package/vendor/fusion/Instances/AttributeOut.luau +63 -63
- package/vendor/fusion/Instances/Child.luau +21 -21
- package/vendor/fusion/Instances/Children.luau +147 -147
- package/vendor/fusion/Instances/Hydrate.luau +32 -32
- package/vendor/fusion/Instances/New.luau +52 -52
- package/vendor/fusion/Instances/OnChange.luau +49 -49
- package/vendor/fusion/Instances/OnEvent.luau +53 -53
- package/vendor/fusion/Instances/Out.luau +69 -69
- package/vendor/fusion/Instances/applyInstanceProps.luau +148 -148
- package/vendor/fusion/Instances/defaultProps.luau +194 -194
- package/vendor/fusion/LICENSE +21 -21
- package/vendor/fusion/Logging/formatError.luau +48 -48
- package/vendor/fusion/Logging/messages.luau +51 -51
- package/vendor/fusion/Logging/parseError.luau +24 -24
- package/vendor/fusion/Memory/checkLifetime.luau +133 -133
- package/vendor/fusion/Memory/deriveScope.luau +23 -23
- package/vendor/fusion/Memory/deriveScopeImpl.luau +44 -44
- package/vendor/fusion/Memory/doCleanup.luau +78 -78
- package/vendor/fusion/Memory/innerScope.luau +33 -33
- package/vendor/fusion/Memory/legacyCleanup.luau +17 -17
- package/vendor/fusion/Memory/needsDestruction.luau +16 -16
- package/vendor/fusion/Memory/poisonScope.luau +33 -33
- package/vendor/fusion/Memory/scopePool.luau +54 -54
- package/vendor/fusion/Memory/scoped.luau +26 -26
- package/vendor/fusion/Memory/whichLivesLonger.luau +74 -74
- package/vendor/fusion/RobloxExternal.luau +97 -97
- package/vendor/fusion/State/Computed.luau +138 -138
- package/vendor/fusion/State/For/Disassembly.luau +210 -210
- package/vendor/fusion/State/For/ForTypes.luau +30 -30
- package/vendor/fusion/State/For/init.luau +109 -109
- package/vendor/fusion/State/ForKeys.luau +93 -93
- package/vendor/fusion/State/ForPairs.luau +96 -96
- package/vendor/fusion/State/ForValues.luau +93 -93
- package/vendor/fusion/State/Value.luau +87 -87
- package/vendor/fusion/State/castToState.luau +25 -25
- package/vendor/fusion/State/peek.luau +30 -30
- package/vendor/fusion/Types.luau +314 -314
- package/vendor/fusion/Utility/Contextual.luau +90 -90
- package/vendor/fusion/Utility/Safe.luau +22 -22
- package/vendor/fusion/Utility/isSimilar.luau +29 -29
- package/vendor/fusion/Utility/merge.luau +35 -35
- package/vendor/fusion/Utility/nameOf.luau +34 -34
- package/vendor/fusion/Utility/never.luau +13 -13
- package/vendor/fusion/Utility/nicknames.luau +10 -10
- package/vendor/fusion/Utility/xtypeof.luau +26 -26
- package/vendor/fusion/init.luau +82 -82
- package/vendor/profilestore/init.luau +2242 -2242
- package/vendor/promise/init.luau +1982 -1982
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -25
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -228
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -269
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -223
- package/vendor/rbxutil/buffer-util/Types.luau +60 -60
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -153
- package/vendor/rbxutil/buffer-util/init.luau +41 -41
- package/vendor/rbxutil/buffer-util/package.json +16 -16
- package/vendor/rbxutil/buffer-util/wally.toml +9 -9
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -232
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -156
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -109
- package/vendor/rbxutil/comm/Client/init.luau +135 -135
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -295
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -211
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -211
- package/vendor/rbxutil/comm/Server/init.luau +140 -140
- package/vendor/rbxutil/comm/Types.luau +18 -18
- package/vendor/rbxutil/comm/Util.luau +27 -27
- package/vendor/rbxutil/comm/init.luau +35 -35
- package/vendor/rbxutil/comm/wally.toml +13 -13
- package/vendor/rbxutil/component/init.luau +759 -759
- package/vendor/rbxutil/component/init.test.luau +311 -311
- package/vendor/rbxutil/component/wally.toml +14 -14
- package/vendor/rbxutil/concur/init.luau +542 -542
- package/vendor/rbxutil/concur/init.test.luau +364 -364
- package/vendor/rbxutil/concur/wally.toml +8 -8
- package/vendor/rbxutil/enum-list/init.luau +101 -101
- package/vendor/rbxutil/enum-list/init.test.luau +91 -91
- package/vendor/rbxutil/enum-list/wally.toml +8 -8
- package/vendor/rbxutil/find/index.d.ts +20 -20
- package/vendor/rbxutil/find/init.luau +44 -44
- package/vendor/rbxutil/find/package.json +17 -17
- package/vendor/rbxutil/find/wally.toml +8 -8
- package/vendor/rbxutil/input/Gamepad.luau +559 -559
- package/vendor/rbxutil/input/Keyboard.luau +124 -124
- package/vendor/rbxutil/input/Mouse.luau +278 -278
- package/vendor/rbxutil/input/PreferredInput.luau +91 -91
- package/vendor/rbxutil/input/Touch.luau +120 -120
- package/vendor/rbxutil/input/init.luau +33 -33
- package/vendor/rbxutil/input/wally.toml +12 -12
- package/vendor/rbxutil/loader/index.d.ts +15 -15
- package/vendor/rbxutil/loader/init.luau +137 -137
- package/vendor/rbxutil/loader/wally.toml +8 -8
- package/vendor/rbxutil/log/index.d.ts +38 -38
- package/vendor/rbxutil/log/init.luau +746 -746
- package/vendor/rbxutil/log/wally.toml +8 -8
- package/vendor/rbxutil/net/init.luau +190 -190
- package/vendor/rbxutil/net/wally.toml +8 -8
- package/vendor/rbxutil/option/index.d.ts +44 -44
- package/vendor/rbxutil/option/init.luau +489 -489
- package/vendor/rbxutil/option/init.test.luau +342 -342
- package/vendor/rbxutil/option/wally.toml +8 -8
- package/vendor/rbxutil/pid/index.d.ts +53 -53
- package/vendor/rbxutil/pid/init.luau +195 -195
- package/vendor/rbxutil/pid/package.json +16 -16
- package/vendor/rbxutil/pid/wally.toml +9 -9
- package/vendor/rbxutil/quaternion/index.d.ts +117 -117
- package/vendor/rbxutil/quaternion/init.luau +570 -570
- package/vendor/rbxutil/quaternion/package.json +16 -16
- package/vendor/rbxutil/quaternion/wally.toml +9 -9
- package/vendor/rbxutil/query/index.d.ts +43 -43
- package/vendor/rbxutil/query/init.luau +117 -117
- package/vendor/rbxutil/query/package.json +18 -18
- package/vendor/rbxutil/query/wally.toml +9 -9
- package/vendor/rbxutil/sequent/index.d.ts +28 -28
- package/vendor/rbxutil/sequent/init.luau +340 -340
- package/vendor/rbxutil/sequent/package.json +16 -16
- package/vendor/rbxutil/sequent/wally.toml +9 -9
- package/vendor/rbxutil/ser/init.luau +175 -175
- package/vendor/rbxutil/ser/init.test.luau +50 -50
- package/vendor/rbxutil/ser/wally.toml +11 -11
- package/vendor/rbxutil/shake/index.d.ts +36 -36
- package/vendor/rbxutil/shake/init.luau +532 -532
- package/vendor/rbxutil/shake/init.test.luau +267 -267
- package/vendor/rbxutil/shake/package.json +16 -16
- package/vendor/rbxutil/shake/wally.toml +9 -9
- package/vendor/rbxutil/signal/index.d.ts +100 -100
- package/vendor/rbxutil/signal/init.luau +432 -432
- package/vendor/rbxutil/signal/init.test.luau +190 -190
- package/vendor/rbxutil/signal/package.json +17 -17
- package/vendor/rbxutil/signal/wally.toml +9 -9
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -65
- package/vendor/rbxutil/silo/Util.luau +55 -55
- package/vendor/rbxutil/silo/init.luau +338 -338
- package/vendor/rbxutil/silo/init.test.luau +215 -215
- package/vendor/rbxutil/silo/wally.toml +8 -8
- package/vendor/rbxutil/spring/index.d.ts +40 -40
- package/vendor/rbxutil/spring/init.luau +97 -97
- package/vendor/rbxutil/spring/package.json +17 -17
- package/vendor/rbxutil/spring/wally.toml +8 -8
- package/vendor/rbxutil/stream/index.d.ts +88 -88
- package/vendor/rbxutil/stream/init.luau +597 -597
- package/vendor/rbxutil/stream/package.json +18 -18
- package/vendor/rbxutil/stream/wally.toml +9 -9
- package/vendor/rbxutil/streamable/Streamable.luau +202 -202
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -80
- package/vendor/rbxutil/streamable/init.luau +8 -8
- package/vendor/rbxutil/streamable/wally.toml +12 -12
- package/vendor/rbxutil/symbol/init.luau +56 -56
- package/vendor/rbxutil/symbol/init.test.luau +37 -37
- package/vendor/rbxutil/symbol/wally.toml +8 -8
- package/vendor/rbxutil/table-util/init.luau +938 -938
- package/vendor/rbxutil/table-util/init.test.luau +439 -439
- package/vendor/rbxutil/task-queue/index.d.ts +27 -27
- package/vendor/rbxutil/task-queue/init.luau +97 -97
- package/vendor/rbxutil/task-queue/wally.toml +8 -8
- package/vendor/rbxutil/timer/index.d.ts +81 -81
- package/vendor/rbxutil/timer/init.luau +249 -249
- package/vendor/rbxutil/timer/init.test.luau +73 -73
- package/vendor/rbxutil/timer/wally.toml +11 -11
- package/vendor/rbxutil/tree/index.d.ts +15 -15
- package/vendor/rbxutil/tree/init.luau +137 -137
- package/vendor/rbxutil/tree/wally.toml +8 -8
- package/vendor/rbxutil/trove/index.d.ts +46 -46
- package/vendor/rbxutil/trove/init.luau +787 -787
- package/vendor/rbxutil/trove/init.test.luau +203 -203
- package/vendor/rbxutil/trove/wally.toml +8 -8
- package/vendor/rbxutil/typed-remote/init.luau +196 -196
- package/vendor/rbxutil/typed-remote/wally.toml +8 -8
- package/vendor/rbxutil/wait-for/index.d.ts +17 -17
- package/vendor/rbxutil/wait-for/init.luau +257 -257
- package/vendor/rbxutil/wait-for/init.test.luau +182 -182
- package/vendor/rbxutil/wait-for/wally.toml +11 -11
- package/vendor/t/t.lua +1350 -1350
- package/vendor/testez/Context.lua +26 -26
- package/vendor/testez/Expectation.lua +311 -311
- package/vendor/testez/ExpectationContext.lua +38 -38
- package/vendor/testez/LifecycleHooks.lua +89 -89
- package/vendor/testez/Reporters/TeamCityReporter.lua +101 -101
- package/vendor/testez/Reporters/TextReporter.lua +105 -105
- package/vendor/testez/Reporters/TextReporterQuiet.lua +96 -96
- package/vendor/testez/TestBootstrap.lua +146 -146
- package/vendor/testez/TestEnum.lua +27 -27
- package/vendor/testez/TestPlan.lua +304 -304
- package/vendor/testez/TestPlanner.lua +39 -39
- package/vendor/testez/TestResults.lua +111 -111
- package/vendor/testez/TestRunner.lua +188 -188
- package/vendor/testez/TestSession.lua +243 -243
- package/vendor/testez/init.lua +39 -39
|
@@ -1,322 +1,322 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
A specialised state object for following a goal state smoothly over time,
|
|
8
|
-
using physics to shape the motion.
|
|
9
|
-
|
|
10
|
-
https://elttob.uk/Fusion/0.3/api-reference/animation/types/spring/
|
|
11
|
-
]]
|
|
12
|
-
|
|
13
|
-
local Package = script.Parent.Parent
|
|
14
|
-
local Types = require(Package.Types)
|
|
15
|
-
local External = require(Package.External)
|
|
16
|
-
-- Memory
|
|
17
|
-
local checkLifetime = require(Package.Memory.checkLifetime)
|
|
18
|
-
-- Graph
|
|
19
|
-
local depend = require(Package.Graph.depend)
|
|
20
|
-
local change = require(Package.Graph.change)
|
|
21
|
-
local evaluate = require(Package.Graph.evaluate)
|
|
22
|
-
-- State
|
|
23
|
-
local castToState = require(Package.State.castToState)
|
|
24
|
-
local peek = require(Package.State.peek)
|
|
25
|
-
-- Animation
|
|
26
|
-
local ExternalTime = require(Package.Animation.ExternalTime)
|
|
27
|
-
local Stopwatch = require(Package.Animation.Stopwatch)
|
|
28
|
-
local packType = require(Package.Animation.packType)
|
|
29
|
-
local unpackType = require(Package.Animation.unpackType)
|
|
30
|
-
local springCoefficients = require(Package.Animation.springCoefficients)
|
|
31
|
-
-- Utility
|
|
32
|
-
local nicknames = require(Package.Utility.nicknames)
|
|
33
|
-
|
|
34
|
-
local EPSILON = 0.00001
|
|
35
|
-
|
|
36
|
-
type Self<T> = Types.Spring<T> & {
|
|
37
|
-
_activeDamping: number,
|
|
38
|
-
_activeGoal: T,
|
|
39
|
-
_activeLatestP: {number},
|
|
40
|
-
_activeLatestV: {number},
|
|
41
|
-
_activeNumSprings: number,
|
|
42
|
-
_activeSpeed: number,
|
|
43
|
-
_activeStartP: {number},
|
|
44
|
-
_activeStartV: {number},
|
|
45
|
-
_activeTargetP: {number},
|
|
46
|
-
_activeType: string,
|
|
47
|
-
_speed: Types.UsedAs<number>,
|
|
48
|
-
_damping: Types.UsedAs<number>,
|
|
49
|
-
_goal: Types.UsedAs<T>,
|
|
50
|
-
_stopwatch: Stopwatch.Stopwatch
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
local class = {}
|
|
54
|
-
class.type = "State"
|
|
55
|
-
class.kind = "Spring"
|
|
56
|
-
class.timeliness = "eager"
|
|
57
|
-
|
|
58
|
-
local METATABLE = table.freeze {__index = class}
|
|
59
|
-
|
|
60
|
-
local function Spring<T>(
|
|
61
|
-
scope: Types.Scope<unknown>,
|
|
62
|
-
goal: Types.UsedAs<T>,
|
|
63
|
-
speed: Types.UsedAs<number>?,
|
|
64
|
-
damping: Types.UsedAs<number>?
|
|
65
|
-
): Types.Spring<T>
|
|
66
|
-
local createdAt = os.clock()
|
|
67
|
-
if typeof(scope) ~= "table" or castToState(scope) ~= nil then
|
|
68
|
-
External.logError("scopeMissing", nil, "Springs", "myScope:Spring(goalState, speed, damping)")
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
local goalState = castToState(goal)
|
|
72
|
-
local stopwatch = nil
|
|
73
|
-
if goalState ~= nil then
|
|
74
|
-
stopwatch = Stopwatch(scope, ExternalTime(scope))
|
|
75
|
-
stopwatch:unpause()
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
local speed = speed or 10
|
|
79
|
-
local damping = damping or 1
|
|
80
|
-
|
|
81
|
-
local self: Self<T> = setmetatable(
|
|
82
|
-
{
|
|
83
|
-
createdAt = createdAt,
|
|
84
|
-
dependencySet = {},
|
|
85
|
-
dependentSet = {},
|
|
86
|
-
lastChange = nil,
|
|
87
|
-
scope = scope,
|
|
88
|
-
validity = "invalid",
|
|
89
|
-
_activeDamping = -1,
|
|
90
|
-
_activeGoal = nil,
|
|
91
|
-
_activeLatestP = {},
|
|
92
|
-
_activeLatestV = {},
|
|
93
|
-
_activeNumSprings = 0,
|
|
94
|
-
_activeSpeed = -1,
|
|
95
|
-
_activeStartP = {},
|
|
96
|
-
_activeStartV = {},
|
|
97
|
-
_activeTargetP = {},
|
|
98
|
-
_activeType = "",
|
|
99
|
-
_damping = damping,
|
|
100
|
-
_EXTREMELY_DANGEROUS_usedAsValue = peek(goal),
|
|
101
|
-
_goal = goal,
|
|
102
|
-
_speed = speed,
|
|
103
|
-
_stopwatch = stopwatch
|
|
104
|
-
},
|
|
105
|
-
METATABLE
|
|
106
|
-
) :: any
|
|
107
|
-
local destroy = function()
|
|
108
|
-
self.scope = nil
|
|
109
|
-
for dependency in pairs(self.dependencySet) do
|
|
110
|
-
dependency.dependentSet[self] = nil
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
self.oldestTask = destroy
|
|
114
|
-
nicknames[self.oldestTask] = "Spring"
|
|
115
|
-
table.insert(scope, destroy)
|
|
116
|
-
|
|
117
|
-
if goalState ~= nil then
|
|
118
|
-
checkLifetime.bOutlivesA(
|
|
119
|
-
scope, self.oldestTask,
|
|
120
|
-
goalState.scope, goalState.oldestTask,
|
|
121
|
-
checkLifetime.formatters.animationGoal
|
|
122
|
-
)
|
|
123
|
-
end
|
|
124
|
-
local speedState = castToState(speed)
|
|
125
|
-
if speedState ~= nil then
|
|
126
|
-
checkLifetime.bOutlivesA(
|
|
127
|
-
scope, self.oldestTask,
|
|
128
|
-
speedState.scope, speedState.oldestTask,
|
|
129
|
-
checkLifetime.formatters.parameter, "speed"
|
|
130
|
-
)
|
|
131
|
-
end
|
|
132
|
-
local dampingState = castToState(damping)
|
|
133
|
-
if dampingState ~= nil then
|
|
134
|
-
checkLifetime.bOutlivesA(
|
|
135
|
-
scope, self.oldestTask,
|
|
136
|
-
dampingState.scope, dampingState.oldestTask,
|
|
137
|
-
checkLifetime.formatters.parameter, "damping"
|
|
138
|
-
)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
-- Eagerly evaluated objects need to evaluate themselves so that they're
|
|
142
|
-
-- valid at all times.
|
|
143
|
-
evaluate(self, true)
|
|
144
|
-
|
|
145
|
-
return self
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
function class.addVelocity<T>(
|
|
149
|
-
self: Self<T>,
|
|
150
|
-
deltaValue: T
|
|
151
|
-
): ()
|
|
152
|
-
evaluate(self, false) -- ensure the _active params are up to date
|
|
153
|
-
local deltaType = typeof(deltaValue)
|
|
154
|
-
if deltaType ~= self._activeType then
|
|
155
|
-
External.logError("springTypeMismatch", nil, deltaType, self._activeType)
|
|
156
|
-
end
|
|
157
|
-
local newStartV = unpackType(deltaValue, deltaType)
|
|
158
|
-
for index, velocity in self._activeLatestV do
|
|
159
|
-
newStartV[index] += velocity
|
|
160
|
-
end
|
|
161
|
-
self._activeStartP = table.clone(self._activeLatestP)
|
|
162
|
-
self._activeStartV = newStartV
|
|
163
|
-
self._stopwatch:zero()
|
|
164
|
-
self._stopwatch:unpause()
|
|
165
|
-
change(self)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
function class.get<T>(
|
|
169
|
-
self: Self<T>
|
|
170
|
-
): never
|
|
171
|
-
return External.logError("stateGetWasRemoved")
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
function class.setPosition<T>(
|
|
175
|
-
self: Self<T>,
|
|
176
|
-
newValue: T
|
|
177
|
-
): ()
|
|
178
|
-
evaluate(self, false) -- ensure the _active params are up to date
|
|
179
|
-
local newType = typeof(newValue)
|
|
180
|
-
if newType ~= self._activeType then
|
|
181
|
-
External.logError("springTypeMismatch", nil, newType, self._activeType)
|
|
182
|
-
end
|
|
183
|
-
self._activeStartP = unpackType(newValue, newType)
|
|
184
|
-
self._activeStartV = table.clone(self._activeLatestV)
|
|
185
|
-
self._stopwatch:zero()
|
|
186
|
-
self._stopwatch:unpause()
|
|
187
|
-
change(self)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
function class.setVelocity<T>(
|
|
191
|
-
self: Self<T>,
|
|
192
|
-
newValue: T
|
|
193
|
-
): ()
|
|
194
|
-
evaluate(self, false) -- ensure the _active params are up to date
|
|
195
|
-
local newType = typeof(newValue)
|
|
196
|
-
if newType ~= self._activeType then
|
|
197
|
-
External.logError("springTypeMismatch", nil, newType, self._activeType)
|
|
198
|
-
end
|
|
199
|
-
self._activeStartP = table.clone(self._activeLatestP)
|
|
200
|
-
self._activeStartV = unpackType(newValue, newType)
|
|
201
|
-
self._stopwatch:zero()
|
|
202
|
-
self._stopwatch:unpause()
|
|
203
|
-
change(self)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
function class._evaluate<T>(
|
|
207
|
-
self: Self<T>
|
|
208
|
-
): boolean
|
|
209
|
-
local goal = castToState(self._goal)
|
|
210
|
-
-- Allow non-state goals to pass through transparently.
|
|
211
|
-
if goal == nil then
|
|
212
|
-
self._EXTREMELY_DANGEROUS_usedAsValue = self._goal :: T
|
|
213
|
-
return false
|
|
214
|
-
end
|
|
215
|
-
-- depend(self, goal)
|
|
216
|
-
local nextFrameGoal = peek(goal)
|
|
217
|
-
-- Protect against NaN goals.
|
|
218
|
-
if nextFrameGoal ~= nextFrameGoal then
|
|
219
|
-
External.logWarn("springNanGoal")
|
|
220
|
-
return false
|
|
221
|
-
end
|
|
222
|
-
local nextFrameGoalType = typeof(nextFrameGoal)
|
|
223
|
-
local discontinuous = nextFrameGoalType ~= self._activeType
|
|
224
|
-
|
|
225
|
-
local stopwatch = self._stopwatch :: Stopwatch.Stopwatch
|
|
226
|
-
local elapsed = peek(stopwatch)
|
|
227
|
-
depend(self, stopwatch)
|
|
228
|
-
|
|
229
|
-
local oldValue = self._EXTREMELY_DANGEROUS_usedAsValue
|
|
230
|
-
local newValue: T
|
|
231
|
-
|
|
232
|
-
if discontinuous then
|
|
233
|
-
-- Propagate changes in type instantly throughout the whole reactive
|
|
234
|
-
-- graph, even if simulation is logically one frame behind, because it
|
|
235
|
-
-- makes the whole graph behave more consistently.
|
|
236
|
-
newValue = nextFrameGoal
|
|
237
|
-
elseif elapsed <= 0 then
|
|
238
|
-
newValue = oldValue
|
|
239
|
-
else
|
|
240
|
-
-- Calculate spring motion.
|
|
241
|
-
-- IMPORTANT: use the parameters from last frame, not this frame. We're
|
|
242
|
-
-- integrating the motion that happened over the last frame, after all.
|
|
243
|
-
-- The stopwatch will have captured the length of time needed correctly.
|
|
244
|
-
local posPos, posVel, velPos, velVel = springCoefficients(
|
|
245
|
-
elapsed,
|
|
246
|
-
self._activeDamping,
|
|
247
|
-
self._activeSpeed
|
|
248
|
-
)
|
|
249
|
-
local isMoving = false
|
|
250
|
-
for index = 1, self._activeNumSprings do
|
|
251
|
-
local startP = self._activeStartP[index]
|
|
252
|
-
local targetP = self._activeTargetP[index]
|
|
253
|
-
local startV = self._activeStartV[index]
|
|
254
|
-
local startD = startP - targetP
|
|
255
|
-
local latestD = startD * posPos + startV * posVel
|
|
256
|
-
local latestV = startD * velPos + startV * velVel
|
|
257
|
-
if latestD ~= latestD or latestV ~= latestV then
|
|
258
|
-
External.logWarn("springNanMotion")
|
|
259
|
-
latestD, latestV = 0, 0
|
|
260
|
-
end
|
|
261
|
-
if math.abs(latestD) > EPSILON or math.abs(latestV) > EPSILON then
|
|
262
|
-
isMoving = true
|
|
263
|
-
end
|
|
264
|
-
local latestP = latestD + targetP
|
|
265
|
-
self._activeLatestP[index] = latestP
|
|
266
|
-
self._activeLatestV[index] = latestV
|
|
267
|
-
end
|
|
268
|
-
-- Sleep and snap to goal if the motion has decayed to a negligible amount.
|
|
269
|
-
if not isMoving then
|
|
270
|
-
for index = 1, self._activeNumSprings do
|
|
271
|
-
self._activeLatestP[index] = self._activeTargetP[index]
|
|
272
|
-
end
|
|
273
|
-
-- TODO: figure out how to do sleeping correctly for single frame
|
|
274
|
-
-- changes
|
|
275
|
-
-- stopwatch:pause()
|
|
276
|
-
-- stopwatch:zero()
|
|
277
|
-
end
|
|
278
|
-
-- Pack springs into final value.
|
|
279
|
-
newValue = packType(self._activeLatestP, self._activeType) :: any
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
-- Reconfigure spring when any of its parameters are changed.
|
|
283
|
-
-- This should happen after integrating the last frame's motion.
|
|
284
|
-
-- NOTE: don't need to add a dependency on these objects! they do not cause
|
|
285
|
-
-- a spring to wake from sleep, so the stopwatch dependency is sufficient.
|
|
286
|
-
local nextFrameSpeed = peek(self._speed) :: number
|
|
287
|
-
local nextFrameDamping = peek(self._damping) :: number
|
|
288
|
-
if
|
|
289
|
-
discontinuous or
|
|
290
|
-
nextFrameGoal ~= self._activeGoal or
|
|
291
|
-
nextFrameSpeed ~= self._activeSpeed or
|
|
292
|
-
nextFrameDamping ~= self._activeDamping
|
|
293
|
-
then
|
|
294
|
-
self._activeTargetP = unpackType(nextFrameGoal, nextFrameGoalType)
|
|
295
|
-
self._activeNumSprings = #self._activeTargetP
|
|
296
|
-
if discontinuous then
|
|
297
|
-
self._activeStartP = table.clone(self._activeTargetP)
|
|
298
|
-
self._activeLatestP = table.clone(self._activeTargetP)
|
|
299
|
-
self._activeStartV = table.create(self._activeNumSprings, 0)
|
|
300
|
-
self._activeLatestV = table.create(self._activeNumSprings, 0)
|
|
301
|
-
else
|
|
302
|
-
self._activeStartP = table.clone(self._activeLatestP)
|
|
303
|
-
self._activeStartV = table.clone(self._activeLatestV)
|
|
304
|
-
end
|
|
305
|
-
self._activeType = nextFrameGoalType
|
|
306
|
-
self._activeGoal = nextFrameGoal
|
|
307
|
-
self._activeDamping = nextFrameDamping
|
|
308
|
-
self._activeSpeed = nextFrameSpeed
|
|
309
|
-
stopwatch:zero()
|
|
310
|
-
stopwatch:unpause()
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
-- Push update and check for similarity.
|
|
314
|
-
-- Don't need to use the similarity test here because this code doesn't
|
|
315
|
-
-- deal with tables, and NaN is already guarded against, so the similarity
|
|
316
|
-
-- test doesn't actually add any new safety here.
|
|
317
|
-
self._EXTREMELY_DANGEROUS_usedAsValue = newValue
|
|
318
|
-
return oldValue ~= newValue
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
table.freeze(class)
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
A specialised state object for following a goal state smoothly over time,
|
|
8
|
+
using physics to shape the motion.
|
|
9
|
+
|
|
10
|
+
https://elttob.uk/Fusion/0.3/api-reference/animation/types/spring/
|
|
11
|
+
]]
|
|
12
|
+
|
|
13
|
+
local Package = script.Parent.Parent
|
|
14
|
+
local Types = require(Package.Types)
|
|
15
|
+
local External = require(Package.External)
|
|
16
|
+
-- Memory
|
|
17
|
+
local checkLifetime = require(Package.Memory.checkLifetime)
|
|
18
|
+
-- Graph
|
|
19
|
+
local depend = require(Package.Graph.depend)
|
|
20
|
+
local change = require(Package.Graph.change)
|
|
21
|
+
local evaluate = require(Package.Graph.evaluate)
|
|
22
|
+
-- State
|
|
23
|
+
local castToState = require(Package.State.castToState)
|
|
24
|
+
local peek = require(Package.State.peek)
|
|
25
|
+
-- Animation
|
|
26
|
+
local ExternalTime = require(Package.Animation.ExternalTime)
|
|
27
|
+
local Stopwatch = require(Package.Animation.Stopwatch)
|
|
28
|
+
local packType = require(Package.Animation.packType)
|
|
29
|
+
local unpackType = require(Package.Animation.unpackType)
|
|
30
|
+
local springCoefficients = require(Package.Animation.springCoefficients)
|
|
31
|
+
-- Utility
|
|
32
|
+
local nicknames = require(Package.Utility.nicknames)
|
|
33
|
+
|
|
34
|
+
local EPSILON = 0.00001
|
|
35
|
+
|
|
36
|
+
type Self<T> = Types.Spring<T> & {
|
|
37
|
+
_activeDamping: number,
|
|
38
|
+
_activeGoal: T,
|
|
39
|
+
_activeLatestP: {number},
|
|
40
|
+
_activeLatestV: {number},
|
|
41
|
+
_activeNumSprings: number,
|
|
42
|
+
_activeSpeed: number,
|
|
43
|
+
_activeStartP: {number},
|
|
44
|
+
_activeStartV: {number},
|
|
45
|
+
_activeTargetP: {number},
|
|
46
|
+
_activeType: string,
|
|
47
|
+
_speed: Types.UsedAs<number>,
|
|
48
|
+
_damping: Types.UsedAs<number>,
|
|
49
|
+
_goal: Types.UsedAs<T>,
|
|
50
|
+
_stopwatch: Stopwatch.Stopwatch
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
local class = {}
|
|
54
|
+
class.type = "State"
|
|
55
|
+
class.kind = "Spring"
|
|
56
|
+
class.timeliness = "eager"
|
|
57
|
+
|
|
58
|
+
local METATABLE = table.freeze {__index = class}
|
|
59
|
+
|
|
60
|
+
local function Spring<T>(
|
|
61
|
+
scope: Types.Scope<unknown>,
|
|
62
|
+
goal: Types.UsedAs<T>,
|
|
63
|
+
speed: Types.UsedAs<number>?,
|
|
64
|
+
damping: Types.UsedAs<number>?
|
|
65
|
+
): Types.Spring<T>
|
|
66
|
+
local createdAt = os.clock()
|
|
67
|
+
if typeof(scope) ~= "table" or castToState(scope) ~= nil then
|
|
68
|
+
External.logError("scopeMissing", nil, "Springs", "myScope:Spring(goalState, speed, damping)")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
local goalState = castToState(goal)
|
|
72
|
+
local stopwatch = nil
|
|
73
|
+
if goalState ~= nil then
|
|
74
|
+
stopwatch = Stopwatch(scope, ExternalTime(scope))
|
|
75
|
+
stopwatch:unpause()
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
local speed = speed or 10
|
|
79
|
+
local damping = damping or 1
|
|
80
|
+
|
|
81
|
+
local self: Self<T> = setmetatable(
|
|
82
|
+
{
|
|
83
|
+
createdAt = createdAt,
|
|
84
|
+
dependencySet = {},
|
|
85
|
+
dependentSet = {},
|
|
86
|
+
lastChange = nil,
|
|
87
|
+
scope = scope,
|
|
88
|
+
validity = "invalid",
|
|
89
|
+
_activeDamping = -1,
|
|
90
|
+
_activeGoal = nil,
|
|
91
|
+
_activeLatestP = {},
|
|
92
|
+
_activeLatestV = {},
|
|
93
|
+
_activeNumSprings = 0,
|
|
94
|
+
_activeSpeed = -1,
|
|
95
|
+
_activeStartP = {},
|
|
96
|
+
_activeStartV = {},
|
|
97
|
+
_activeTargetP = {},
|
|
98
|
+
_activeType = "",
|
|
99
|
+
_damping = damping,
|
|
100
|
+
_EXTREMELY_DANGEROUS_usedAsValue = peek(goal),
|
|
101
|
+
_goal = goal,
|
|
102
|
+
_speed = speed,
|
|
103
|
+
_stopwatch = stopwatch
|
|
104
|
+
},
|
|
105
|
+
METATABLE
|
|
106
|
+
) :: any
|
|
107
|
+
local destroy = function()
|
|
108
|
+
self.scope = nil
|
|
109
|
+
for dependency in pairs(self.dependencySet) do
|
|
110
|
+
dependency.dependentSet[self] = nil
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
self.oldestTask = destroy
|
|
114
|
+
nicknames[self.oldestTask] = "Spring"
|
|
115
|
+
table.insert(scope, destroy)
|
|
116
|
+
|
|
117
|
+
if goalState ~= nil then
|
|
118
|
+
checkLifetime.bOutlivesA(
|
|
119
|
+
scope, self.oldestTask,
|
|
120
|
+
goalState.scope, goalState.oldestTask,
|
|
121
|
+
checkLifetime.formatters.animationGoal
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
local speedState = castToState(speed)
|
|
125
|
+
if speedState ~= nil then
|
|
126
|
+
checkLifetime.bOutlivesA(
|
|
127
|
+
scope, self.oldestTask,
|
|
128
|
+
speedState.scope, speedState.oldestTask,
|
|
129
|
+
checkLifetime.formatters.parameter, "speed"
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
local dampingState = castToState(damping)
|
|
133
|
+
if dampingState ~= nil then
|
|
134
|
+
checkLifetime.bOutlivesA(
|
|
135
|
+
scope, self.oldestTask,
|
|
136
|
+
dampingState.scope, dampingState.oldestTask,
|
|
137
|
+
checkLifetime.formatters.parameter, "damping"
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
-- Eagerly evaluated objects need to evaluate themselves so that they're
|
|
142
|
+
-- valid at all times.
|
|
143
|
+
evaluate(self, true)
|
|
144
|
+
|
|
145
|
+
return self
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
function class.addVelocity<T>(
|
|
149
|
+
self: Self<T>,
|
|
150
|
+
deltaValue: T
|
|
151
|
+
): ()
|
|
152
|
+
evaluate(self, false) -- ensure the _active params are up to date
|
|
153
|
+
local deltaType = typeof(deltaValue)
|
|
154
|
+
if deltaType ~= self._activeType then
|
|
155
|
+
External.logError("springTypeMismatch", nil, deltaType, self._activeType)
|
|
156
|
+
end
|
|
157
|
+
local newStartV = unpackType(deltaValue, deltaType)
|
|
158
|
+
for index, velocity in self._activeLatestV do
|
|
159
|
+
newStartV[index] += velocity
|
|
160
|
+
end
|
|
161
|
+
self._activeStartP = table.clone(self._activeLatestP)
|
|
162
|
+
self._activeStartV = newStartV
|
|
163
|
+
self._stopwatch:zero()
|
|
164
|
+
self._stopwatch:unpause()
|
|
165
|
+
change(self)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
function class.get<T>(
|
|
169
|
+
self: Self<T>
|
|
170
|
+
): never
|
|
171
|
+
return External.logError("stateGetWasRemoved")
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
function class.setPosition<T>(
|
|
175
|
+
self: Self<T>,
|
|
176
|
+
newValue: T
|
|
177
|
+
): ()
|
|
178
|
+
evaluate(self, false) -- ensure the _active params are up to date
|
|
179
|
+
local newType = typeof(newValue)
|
|
180
|
+
if newType ~= self._activeType then
|
|
181
|
+
External.logError("springTypeMismatch", nil, newType, self._activeType)
|
|
182
|
+
end
|
|
183
|
+
self._activeStartP = unpackType(newValue, newType)
|
|
184
|
+
self._activeStartV = table.clone(self._activeLatestV)
|
|
185
|
+
self._stopwatch:zero()
|
|
186
|
+
self._stopwatch:unpause()
|
|
187
|
+
change(self)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
function class.setVelocity<T>(
|
|
191
|
+
self: Self<T>,
|
|
192
|
+
newValue: T
|
|
193
|
+
): ()
|
|
194
|
+
evaluate(self, false) -- ensure the _active params are up to date
|
|
195
|
+
local newType = typeof(newValue)
|
|
196
|
+
if newType ~= self._activeType then
|
|
197
|
+
External.logError("springTypeMismatch", nil, newType, self._activeType)
|
|
198
|
+
end
|
|
199
|
+
self._activeStartP = table.clone(self._activeLatestP)
|
|
200
|
+
self._activeStartV = unpackType(newValue, newType)
|
|
201
|
+
self._stopwatch:zero()
|
|
202
|
+
self._stopwatch:unpause()
|
|
203
|
+
change(self)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
function class._evaluate<T>(
|
|
207
|
+
self: Self<T>
|
|
208
|
+
): boolean
|
|
209
|
+
local goal = castToState(self._goal)
|
|
210
|
+
-- Allow non-state goals to pass through transparently.
|
|
211
|
+
if goal == nil then
|
|
212
|
+
self._EXTREMELY_DANGEROUS_usedAsValue = self._goal :: T
|
|
213
|
+
return false
|
|
214
|
+
end
|
|
215
|
+
-- depend(self, goal)
|
|
216
|
+
local nextFrameGoal = peek(goal)
|
|
217
|
+
-- Protect against NaN goals.
|
|
218
|
+
if nextFrameGoal ~= nextFrameGoal then
|
|
219
|
+
External.logWarn("springNanGoal")
|
|
220
|
+
return false
|
|
221
|
+
end
|
|
222
|
+
local nextFrameGoalType = typeof(nextFrameGoal)
|
|
223
|
+
local discontinuous = nextFrameGoalType ~= self._activeType
|
|
224
|
+
|
|
225
|
+
local stopwatch = self._stopwatch :: Stopwatch.Stopwatch
|
|
226
|
+
local elapsed = peek(stopwatch)
|
|
227
|
+
depend(self, stopwatch)
|
|
228
|
+
|
|
229
|
+
local oldValue = self._EXTREMELY_DANGEROUS_usedAsValue
|
|
230
|
+
local newValue: T
|
|
231
|
+
|
|
232
|
+
if discontinuous then
|
|
233
|
+
-- Propagate changes in type instantly throughout the whole reactive
|
|
234
|
+
-- graph, even if simulation is logically one frame behind, because it
|
|
235
|
+
-- makes the whole graph behave more consistently.
|
|
236
|
+
newValue = nextFrameGoal
|
|
237
|
+
elseif elapsed <= 0 then
|
|
238
|
+
newValue = oldValue
|
|
239
|
+
else
|
|
240
|
+
-- Calculate spring motion.
|
|
241
|
+
-- IMPORTANT: use the parameters from last frame, not this frame. We're
|
|
242
|
+
-- integrating the motion that happened over the last frame, after all.
|
|
243
|
+
-- The stopwatch will have captured the length of time needed correctly.
|
|
244
|
+
local posPos, posVel, velPos, velVel = springCoefficients(
|
|
245
|
+
elapsed,
|
|
246
|
+
self._activeDamping,
|
|
247
|
+
self._activeSpeed
|
|
248
|
+
)
|
|
249
|
+
local isMoving = false
|
|
250
|
+
for index = 1, self._activeNumSprings do
|
|
251
|
+
local startP = self._activeStartP[index]
|
|
252
|
+
local targetP = self._activeTargetP[index]
|
|
253
|
+
local startV = self._activeStartV[index]
|
|
254
|
+
local startD = startP - targetP
|
|
255
|
+
local latestD = startD * posPos + startV * posVel
|
|
256
|
+
local latestV = startD * velPos + startV * velVel
|
|
257
|
+
if latestD ~= latestD or latestV ~= latestV then
|
|
258
|
+
External.logWarn("springNanMotion")
|
|
259
|
+
latestD, latestV = 0, 0
|
|
260
|
+
end
|
|
261
|
+
if math.abs(latestD) > EPSILON or math.abs(latestV) > EPSILON then
|
|
262
|
+
isMoving = true
|
|
263
|
+
end
|
|
264
|
+
local latestP = latestD + targetP
|
|
265
|
+
self._activeLatestP[index] = latestP
|
|
266
|
+
self._activeLatestV[index] = latestV
|
|
267
|
+
end
|
|
268
|
+
-- Sleep and snap to goal if the motion has decayed to a negligible amount.
|
|
269
|
+
if not isMoving then
|
|
270
|
+
for index = 1, self._activeNumSprings do
|
|
271
|
+
self._activeLatestP[index] = self._activeTargetP[index]
|
|
272
|
+
end
|
|
273
|
+
-- TODO: figure out how to do sleeping correctly for single frame
|
|
274
|
+
-- changes
|
|
275
|
+
-- stopwatch:pause()
|
|
276
|
+
-- stopwatch:zero()
|
|
277
|
+
end
|
|
278
|
+
-- Pack springs into final value.
|
|
279
|
+
newValue = packType(self._activeLatestP, self._activeType) :: any
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
-- Reconfigure spring when any of its parameters are changed.
|
|
283
|
+
-- This should happen after integrating the last frame's motion.
|
|
284
|
+
-- NOTE: don't need to add a dependency on these objects! they do not cause
|
|
285
|
+
-- a spring to wake from sleep, so the stopwatch dependency is sufficient.
|
|
286
|
+
local nextFrameSpeed = peek(self._speed) :: number
|
|
287
|
+
local nextFrameDamping = peek(self._damping) :: number
|
|
288
|
+
if
|
|
289
|
+
discontinuous or
|
|
290
|
+
nextFrameGoal ~= self._activeGoal or
|
|
291
|
+
nextFrameSpeed ~= self._activeSpeed or
|
|
292
|
+
nextFrameDamping ~= self._activeDamping
|
|
293
|
+
then
|
|
294
|
+
self._activeTargetP = unpackType(nextFrameGoal, nextFrameGoalType)
|
|
295
|
+
self._activeNumSprings = #self._activeTargetP
|
|
296
|
+
if discontinuous then
|
|
297
|
+
self._activeStartP = table.clone(self._activeTargetP)
|
|
298
|
+
self._activeLatestP = table.clone(self._activeTargetP)
|
|
299
|
+
self._activeStartV = table.create(self._activeNumSprings, 0)
|
|
300
|
+
self._activeLatestV = table.create(self._activeNumSprings, 0)
|
|
301
|
+
else
|
|
302
|
+
self._activeStartP = table.clone(self._activeLatestP)
|
|
303
|
+
self._activeStartV = table.clone(self._activeLatestV)
|
|
304
|
+
end
|
|
305
|
+
self._activeType = nextFrameGoalType
|
|
306
|
+
self._activeGoal = nextFrameGoal
|
|
307
|
+
self._activeDamping = nextFrameDamping
|
|
308
|
+
self._activeSpeed = nextFrameSpeed
|
|
309
|
+
stopwatch:zero()
|
|
310
|
+
stopwatch:unpause()
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
-- Push update and check for similarity.
|
|
314
|
+
-- Don't need to use the similarity test here because this code doesn't
|
|
315
|
+
-- deal with tables, and NaN is already guarded against, so the similarity
|
|
316
|
+
-- test doesn't actually add any new safety here.
|
|
317
|
+
self._EXTREMELY_DANGEROUS_usedAsValue = newValue
|
|
318
|
+
return oldValue ~= newValue
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
table.freeze(class)
|
|
322
322
|
return Spring :: Types.SpringConstructor
|