roblox-opencode 1.0.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/README.md +122 -0
- package/commands/setup-game.md +108 -0
- package/commands/sync-check.md +53 -0
- package/core/roblox-core.md +93 -0
- package/dist/server.js +167 -0
- package/package.json +35 -0
- package/skills/roblox-analytics/SKILL.md +277 -0
- package/skills/roblox-analytics/references/event-batcher.luau +75 -0
- package/skills/roblox-animation-vfx/SKILL.md +1325 -0
- package/skills/roblox-architecture/SKILL.md +863 -0
- package/skills/roblox-architecture/references/combat-systems.md +1381 -0
- package/skills/roblox-code-review/SKILL.md +687 -0
- package/skills/roblox-data/SKILL.md +889 -0
- package/skills/roblox-data/references/inventory-systems.md +1729 -0
- package/skills/roblox-debug/SKILL.md +99 -0
- package/skills/roblox-gui/SKILL.md +1103 -0
- package/skills/roblox-gui-fusion/SKILL.md +150 -0
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
- package/skills/roblox-gui-fusion/references/shop.luau +411 -0
- package/skills/roblox-luau-mastery/SKILL.md +1519 -0
- package/skills/roblox-monetization/SKILL.md +1084 -0
- package/skills/roblox-monetization/references/process-receipt.luau +131 -0
- package/skills/roblox-networking/SKILL.md +669 -0
- package/skills/roblox-networking/references/remote-validator.luau +193 -0
- package/skills/roblox-publish-checklist/SKILL.md +128 -0
- package/skills/roblox-runtime/SKILL.md +753 -0
- package/skills/roblox-sharp-edges/SKILL.md +295 -0
- package/skills/roblox-sync/SKILL.md +126 -0
- package/skills/roblox-testing/SKILL.md +943 -0
- package/skills/roblox-tooling/SKILL.md +150 -0
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
- package/vendor/LICENSES/promise-LICENSE +21 -0
- package/vendor/LICENSES/t-LICENSE +21 -0
- package/vendor/LICENSES/testez-LICENSE +201 -0
- package/vendor/README.md +84 -0
- package/vendor/fusion/Animation/ExternalTime.luau +84 -0
- package/vendor/fusion/Animation/Spring.luau +322 -0
- package/vendor/fusion/Animation/Stopwatch.luau +128 -0
- package/vendor/fusion/Animation/Tween.luau +187 -0
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
- package/vendor/fusion/Animation/lerpType.luau +164 -0
- package/vendor/fusion/Animation/packType.luau +100 -0
- package/vendor/fusion/Animation/springCoefficients.luau +80 -0
- package/vendor/fusion/Animation/unpackType.luau +103 -0
- package/vendor/fusion/Colour/Oklab.luau +70 -0
- package/vendor/fusion/Colour/sRGB.luau +55 -0
- package/vendor/fusion/External.luau +168 -0
- package/vendor/fusion/ExternalDebug.luau +70 -0
- package/vendor/fusion/Graph/Observer.luau +114 -0
- package/vendor/fusion/Graph/castToGraph.luau +29 -0
- package/vendor/fusion/Graph/change.luau +81 -0
- package/vendor/fusion/Graph/depend.luau +33 -0
- package/vendor/fusion/Graph/evaluate.luau +56 -0
- package/vendor/fusion/Instances/Attribute.luau +58 -0
- package/vendor/fusion/Instances/AttributeChange.luau +47 -0
- package/vendor/fusion/Instances/AttributeOut.luau +63 -0
- package/vendor/fusion/Instances/Child.luau +21 -0
- package/vendor/fusion/Instances/Children.luau +148 -0
- package/vendor/fusion/Instances/Hydrate.luau +33 -0
- package/vendor/fusion/Instances/New.luau +53 -0
- package/vendor/fusion/Instances/OnChange.luau +50 -0
- package/vendor/fusion/Instances/OnEvent.luau +54 -0
- package/vendor/fusion/Instances/Out.luau +69 -0
- package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
- package/vendor/fusion/Instances/defaultProps.luau +194 -0
- package/vendor/fusion/LICENSE +21 -0
- package/vendor/fusion/Logging/formatError.luau +49 -0
- package/vendor/fusion/Logging/messages.luau +52 -0
- package/vendor/fusion/Logging/parseError.luau +25 -0
- package/vendor/fusion/Memory/checkLifetime.luau +134 -0
- package/vendor/fusion/Memory/deriveScope.luau +24 -0
- package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
- package/vendor/fusion/Memory/doCleanup.luau +79 -0
- package/vendor/fusion/Memory/innerScope.luau +34 -0
- package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
- package/vendor/fusion/Memory/needsDestruction.luau +17 -0
- package/vendor/fusion/Memory/poisonScope.luau +34 -0
- package/vendor/fusion/Memory/scopePool.luau +55 -0
- package/vendor/fusion/Memory/scoped.luau +27 -0
- package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
- package/vendor/fusion/RobloxExternal.luau +98 -0
- package/vendor/fusion/State/Computed.luau +139 -0
- package/vendor/fusion/State/For/Disassembly.luau +211 -0
- package/vendor/fusion/State/For/ForTypes.luau +30 -0
- package/vendor/fusion/State/For/init.luau +110 -0
- package/vendor/fusion/State/ForKeys.luau +94 -0
- package/vendor/fusion/State/ForPairs.luau +97 -0
- package/vendor/fusion/State/ForValues.luau +94 -0
- package/vendor/fusion/State/Value.luau +88 -0
- package/vendor/fusion/State/castToState.luau +26 -0
- package/vendor/fusion/State/peek.luau +31 -0
- package/vendor/fusion/State/updateAll.luau +1 -0
- package/vendor/fusion/Types.luau +314 -0
- package/vendor/fusion/Utility/Contextual.luau +91 -0
- package/vendor/fusion/Utility/Safe.luau +23 -0
- package/vendor/fusion/Utility/isSimilar.luau +29 -0
- package/vendor/fusion/Utility/merge.luau +35 -0
- package/vendor/fusion/Utility/nameOf.luau +35 -0
- package/vendor/fusion/Utility/never.luau +14 -0
- package/vendor/fusion/Utility/nicknames.luau +11 -0
- package/vendor/fusion/Utility/xtypeof.luau +27 -0
- package/vendor/fusion/init.luau +82 -0
- package/vendor/profilestore/init.luau +2243 -0
- package/vendor/promise/init.luau +1982 -0
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
- package/vendor/rbxutil/buffer-util/Types.luau +60 -0
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
- package/vendor/rbxutil/buffer-util/init.luau +41 -0
- package/vendor/rbxutil/buffer-util/package.json +16 -0
- package/vendor/rbxutil/buffer-util/wally.toml +9 -0
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
- package/vendor/rbxutil/comm/Client/init.luau +135 -0
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
- package/vendor/rbxutil/comm/Server/init.luau +140 -0
- package/vendor/rbxutil/comm/Types.luau +18 -0
- package/vendor/rbxutil/comm/Util.luau +27 -0
- package/vendor/rbxutil/comm/init.luau +35 -0
- package/vendor/rbxutil/comm/wally.toml +13 -0
- package/vendor/rbxutil/component/init.luau +759 -0
- package/vendor/rbxutil/component/init.test.luau +311 -0
- package/vendor/rbxutil/component/wally.toml +14 -0
- package/vendor/rbxutil/concur/init.luau +542 -0
- package/vendor/rbxutil/concur/init.test.luau +364 -0
- package/vendor/rbxutil/concur/wally.toml +8 -0
- package/vendor/rbxutil/enum-list/init.luau +101 -0
- package/vendor/rbxutil/enum-list/init.test.luau +91 -0
- package/vendor/rbxutil/enum-list/wally.toml +8 -0
- package/vendor/rbxutil/find/index.d.ts +20 -0
- package/vendor/rbxutil/find/init.luau +44 -0
- package/vendor/rbxutil/find/package.json +17 -0
- package/vendor/rbxutil/find/wally.toml +8 -0
- package/vendor/rbxutil/input/Gamepad.luau +559 -0
- package/vendor/rbxutil/input/Keyboard.luau +124 -0
- package/vendor/rbxutil/input/Mouse.luau +278 -0
- package/vendor/rbxutil/input/PreferredInput.luau +91 -0
- package/vendor/rbxutil/input/Touch.luau +120 -0
- package/vendor/rbxutil/input/init.luau +33 -0
- package/vendor/rbxutil/input/wally.toml +12 -0
- package/vendor/rbxutil/loader/index.d.ts +15 -0
- package/vendor/rbxutil/loader/init.luau +137 -0
- package/vendor/rbxutil/loader/wally.toml +8 -0
- package/vendor/rbxutil/log/index.d.ts +38 -0
- package/vendor/rbxutil/log/init.luau +746 -0
- package/vendor/rbxutil/log/wally.toml +8 -0
- package/vendor/rbxutil/net/init.luau +190 -0
- package/vendor/rbxutil/net/wally.toml +8 -0
- package/vendor/rbxutil/option/index.d.ts +44 -0
- package/vendor/rbxutil/option/init.luau +489 -0
- package/vendor/rbxutil/option/init.test.luau +342 -0
- package/vendor/rbxutil/option/wally.toml +8 -0
- package/vendor/rbxutil/pid/index.d.ts +53 -0
- package/vendor/rbxutil/pid/init.luau +195 -0
- package/vendor/rbxutil/pid/package.json +16 -0
- package/vendor/rbxutil/pid/wally.toml +9 -0
- package/vendor/rbxutil/quaternion/index.d.ts +117 -0
- package/vendor/rbxutil/quaternion/init.luau +570 -0
- package/vendor/rbxutil/quaternion/package.json +16 -0
- package/vendor/rbxutil/quaternion/wally.toml +9 -0
- package/vendor/rbxutil/query/index.d.ts +43 -0
- package/vendor/rbxutil/query/init.luau +117 -0
- package/vendor/rbxutil/query/package.json +18 -0
- package/vendor/rbxutil/query/wally.toml +9 -0
- package/vendor/rbxutil/sequent/index.d.ts +28 -0
- package/vendor/rbxutil/sequent/init.luau +340 -0
- package/vendor/rbxutil/sequent/package.json +16 -0
- package/vendor/rbxutil/sequent/wally.toml +9 -0
- package/vendor/rbxutil/ser/init.luau +175 -0
- package/vendor/rbxutil/ser/init.test.luau +50 -0
- package/vendor/rbxutil/ser/wally.toml +11 -0
- package/vendor/rbxutil/shake/index.d.ts +36 -0
- package/vendor/rbxutil/shake/init.luau +532 -0
- package/vendor/rbxutil/shake/init.test.luau +267 -0
- package/vendor/rbxutil/shake/package.json +16 -0
- package/vendor/rbxutil/shake/wally.toml +9 -0
- package/vendor/rbxutil/signal/index.d.ts +100 -0
- package/vendor/rbxutil/signal/init.luau +432 -0
- package/vendor/rbxutil/signal/init.test.luau +190 -0
- package/vendor/rbxutil/signal/package.json +17 -0
- package/vendor/rbxutil/signal/wally.toml +9 -0
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
- package/vendor/rbxutil/silo/Util.luau +55 -0
- package/vendor/rbxutil/silo/init.luau +338 -0
- package/vendor/rbxutil/silo/init.test.luau +215 -0
- package/vendor/rbxutil/silo/wally.toml +8 -0
- package/vendor/rbxutil/spring/index.d.ts +40 -0
- package/vendor/rbxutil/spring/init.luau +97 -0
- package/vendor/rbxutil/spring/package.json +17 -0
- package/vendor/rbxutil/spring/wally.toml +8 -0
- package/vendor/rbxutil/stream/index.d.ts +88 -0
- package/vendor/rbxutil/stream/init.luau +597 -0
- package/vendor/rbxutil/stream/package.json +18 -0
- package/vendor/rbxutil/stream/wally.toml +9 -0
- package/vendor/rbxutil/streamable/Streamable.luau +202 -0
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
- package/vendor/rbxutil/streamable/init.luau +8 -0
- package/vendor/rbxutil/streamable/wally.toml +12 -0
- package/vendor/rbxutil/symbol/init.luau +56 -0
- package/vendor/rbxutil/symbol/init.test.luau +37 -0
- package/vendor/rbxutil/symbol/wally.toml +8 -0
- package/vendor/rbxutil/table-util/init.luau +938 -0
- package/vendor/rbxutil/table-util/init.test.luau +439 -0
- package/vendor/rbxutil/table-util/wally.toml +8 -0
- package/vendor/rbxutil/task-queue/index.d.ts +27 -0
- package/vendor/rbxutil/task-queue/init.luau +97 -0
- package/vendor/rbxutil/task-queue/wally.toml +8 -0
- package/vendor/rbxutil/timer/index.d.ts +81 -0
- package/vendor/rbxutil/timer/init.luau +249 -0
- package/vendor/rbxutil/timer/init.test.luau +73 -0
- package/vendor/rbxutil/timer/wally.toml +11 -0
- package/vendor/rbxutil/tree/index.d.ts +15 -0
- package/vendor/rbxutil/tree/init.luau +137 -0
- package/vendor/rbxutil/tree/wally.toml +8 -0
- package/vendor/rbxutil/trove/index.d.ts +46 -0
- package/vendor/rbxutil/trove/init.luau +787 -0
- package/vendor/rbxutil/trove/init.test.luau +203 -0
- package/vendor/rbxutil/trove/wally.toml +8 -0
- package/vendor/rbxutil/typed-remote/init.luau +196 -0
- package/vendor/rbxutil/typed-remote/wally.toml +8 -0
- package/vendor/rbxutil/wait-for/index.d.ts +17 -0
- package/vendor/rbxutil/wait-for/init.luau +257 -0
- package/vendor/rbxutil/wait-for/init.test.luau +182 -0
- package/vendor/rbxutil/wait-for/wally.toml +11 -0
- package/vendor/t/t.lua +1350 -0
- package/vendor/testez/Context.lua +26 -0
- package/vendor/testez/Expectation.lua +311 -0
- package/vendor/testez/ExpectationContext.lua +38 -0
- package/vendor/testez/LifecycleHooks.lua +89 -0
- package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
- package/vendor/testez/Reporters/TextReporter.lua +106 -0
- package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
- package/vendor/testez/TestBootstrap.lua +147 -0
- package/vendor/testez/TestEnum.lua +28 -0
- package/vendor/testez/TestPlan.lua +304 -0
- package/vendor/testez/TestPlanner.lua +40 -0
- package/vendor/testez/TestResults.lua +112 -0
- package/vendor/testez/TestRunner.lua +188 -0
- package/vendor/testez/TestSession.lua +243 -0
- package/vendor/testez/init.lua +40 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
--!native
|
|
2
|
+
|
|
3
|
+
local RunService = game:GetService("RunService")
|
|
4
|
+
|
|
5
|
+
--[=[
|
|
6
|
+
@within Shake
|
|
7
|
+
@type UpdateCallbackFn () -> (position: Vector3, rotation: Vector3, completed: boolean)
|
|
8
|
+
]=]
|
|
9
|
+
type UpdateCallbackFn = () -> (Vector3, Vector3, boolean)
|
|
10
|
+
|
|
11
|
+
export type Shake = {
|
|
12
|
+
Amplitude: number,
|
|
13
|
+
Frequency: number,
|
|
14
|
+
FadeInTime: number,
|
|
15
|
+
FadeOutTime: number,
|
|
16
|
+
SustainTime: number,
|
|
17
|
+
Sustain: boolean,
|
|
18
|
+
PositionInfluence: Vector3,
|
|
19
|
+
RotationInfluence: Vector3,
|
|
20
|
+
TimeFunction: () -> number,
|
|
21
|
+
|
|
22
|
+
Start: (self: Shake) -> (),
|
|
23
|
+
Stop: (self: Shake) -> (),
|
|
24
|
+
IsShaking: (self: Shake) -> boolean,
|
|
25
|
+
StopSustain: (self: Shake) -> (),
|
|
26
|
+
Update: (self: Shake) -> (Vector3, Vector3, boolean),
|
|
27
|
+
OnSignal: (
|
|
28
|
+
self: Shake,
|
|
29
|
+
signal: RBXScriptSignal,
|
|
30
|
+
callback: (Vector3, Vector3, boolean) -> ()
|
|
31
|
+
) -> RBXScriptConnection,
|
|
32
|
+
BindToRenderStep: (self: Shake, name: string, priority: number, callback: (Vector3, Vector3, boolean) -> ()) -> (),
|
|
33
|
+
Clone: (self: Shake) -> Shake,
|
|
34
|
+
Destroy: (self: Shake) -> (),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
local rng = Random.new()
|
|
38
|
+
local renderId = 0
|
|
39
|
+
|
|
40
|
+
--[=[
|
|
41
|
+
@class Shake
|
|
42
|
+
Create realistic shake effects, such as camera or object shakes.
|
|
43
|
+
|
|
44
|
+
Creating a shake is very simple with this module. For every shake,
|
|
45
|
+
simply create a shake instance by calling `Shake.new()`. From
|
|
46
|
+
there, configure the shake however desired. Once configured,
|
|
47
|
+
call `shake:Start()` and then bind a function to it with either
|
|
48
|
+
`shake:OnSignal(...)` or `shake:BindToRenderStep(...)`.
|
|
49
|
+
|
|
50
|
+
The shake will output its values to the connected function, and then
|
|
51
|
+
automatically stop and clean up its connections once completed.
|
|
52
|
+
|
|
53
|
+
Shake instances can be reused indefinitely. However, only one shake
|
|
54
|
+
operation per instance can be running. If more than one is needed
|
|
55
|
+
of the same configuration, simply call `shake:Clone()` to duplicate
|
|
56
|
+
it.
|
|
57
|
+
|
|
58
|
+
Example of a simple camera shake:
|
|
59
|
+
```lua
|
|
60
|
+
local priority = Enum.RenderPriority.Last.Value
|
|
61
|
+
|
|
62
|
+
local shake = Shake.new()
|
|
63
|
+
shake.FadeInTime = 0
|
|
64
|
+
shake.Frequency = 0.1
|
|
65
|
+
shake.Amplitude = 5
|
|
66
|
+
shake.RotationInfluence = Vector3.new(0.1, 0.1, 0.1)
|
|
67
|
+
|
|
68
|
+
shake:Start()
|
|
69
|
+
shake:BindToRenderStep(Shake.NextRenderName(), priority, function(pos, rot, isDone)
|
|
70
|
+
camera.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
|
|
71
|
+
end)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Shakes will automatically stop once the shake has been completed. Shakes can
|
|
75
|
+
also be used continuously if the `Sustain` property is set to `true`.
|
|
76
|
+
|
|
77
|
+
## Fixing drift
|
|
78
|
+
|
|
79
|
+
If you are not controlling the initial CFrame of the camera (i.e. using Roblox's camera scripts),
|
|
80
|
+
then you might run into odd behavior with the above example. This is because Roblox's camera
|
|
81
|
+
scripts are influenced by the current CFrame value of the camera. Thus, the shake effect causes
|
|
82
|
+
odd side-effects, especially noticeable at higher FPS.
|
|
83
|
+
|
|
84
|
+
The solution is to simply store the camera's CFrame before applying the shake CFrame, and then
|
|
85
|
+
reapplying this stored CFrame value after rendering is complete (e.g. on Heartbeat).
|
|
86
|
+
|
|
87
|
+
```lua
|
|
88
|
+
local camCf: CFrame
|
|
89
|
+
|
|
90
|
+
shake:BindToRenderStep(Shake.NextRenderName(), priority, function(pos, rot, isDone)
|
|
91
|
+
-- Store the CFrame value that was set from Roblox's camera scripts:
|
|
92
|
+
camCf = camera.CFrame
|
|
93
|
+
|
|
94
|
+
camera.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
|
|
95
|
+
end)
|
|
96
|
+
|
|
97
|
+
RunService.Heartbeat:Connect(function()
|
|
98
|
+
-- Reapply the camera script CFrame before they run again.
|
|
99
|
+
-- Heartbeat runs AFTER Roblox has rendered, so it will not affect the camera this frame.
|
|
100
|
+
camera.CFrame = camCf
|
|
101
|
+
end)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Here are some more helpful configuration examples:
|
|
107
|
+
|
|
108
|
+
```lua
|
|
109
|
+
local shake = Shake.new()
|
|
110
|
+
|
|
111
|
+
-- The magnitude of the shake. Larger numbers means larger shakes.
|
|
112
|
+
shake.Amplitude = 5
|
|
113
|
+
|
|
114
|
+
-- The speed of the shake. Smaller frequencies mean faster shakes.
|
|
115
|
+
shake.Frequency = 0.1
|
|
116
|
+
|
|
117
|
+
-- Fade-in time before max amplitude shake. Set to 0 for immediate shake.
|
|
118
|
+
shake.FadeInTime = 0
|
|
119
|
+
|
|
120
|
+
-- Fade-out time. Set to 0 for immediate cutoff.
|
|
121
|
+
shake.FadeOutTime = 0
|
|
122
|
+
|
|
123
|
+
-- How long the shake sustains full amplitude before fading out
|
|
124
|
+
shake.SustainTime = 1
|
|
125
|
+
|
|
126
|
+
-- Set to true to never end the shake. Call shake:StopSustain() to start the fade-out.
|
|
127
|
+
shake.Sustain = true
|
|
128
|
+
|
|
129
|
+
-- Multiplies against the shake vector to control the final amplitude of the position.
|
|
130
|
+
-- Can be seen internally as: position = shakeVector * fadeInOut * positionInfluence
|
|
131
|
+
shake.PositionInfluence = Vector3.one
|
|
132
|
+
|
|
133
|
+
-- Multiplies against the shake vector to control the final amplitude of the rotation.
|
|
134
|
+
-- Can be seen internally as: position = shakeVector * fadeInOut * rotationInfluence
|
|
135
|
+
shake.RotationInfluence = Vector3.new(0.1, 0.1, 0.1)
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
]=]
|
|
139
|
+
local Shake = {}
|
|
140
|
+
Shake.__index = Shake
|
|
141
|
+
|
|
142
|
+
--[=[
|
|
143
|
+
@within Shake
|
|
144
|
+
@prop Amplitude number
|
|
145
|
+
Amplitude of the overall shake. For instance, an amplitude of `3` would mean the
|
|
146
|
+
peak magnitude for the outputted shake vectors would be about `3`.
|
|
147
|
+
|
|
148
|
+
Defaults to `1`.
|
|
149
|
+
]=]
|
|
150
|
+
|
|
151
|
+
--[=[
|
|
152
|
+
@within Shake
|
|
153
|
+
@prop Frequency number
|
|
154
|
+
Frequency of the overall shake. This changes how slow or fast the
|
|
155
|
+
shake occurs.
|
|
156
|
+
|
|
157
|
+
Defaults to `1`.
|
|
158
|
+
]=]
|
|
159
|
+
|
|
160
|
+
--[=[
|
|
161
|
+
@within Shake
|
|
162
|
+
@prop FadeInTime number
|
|
163
|
+
How long it takes for the shake to fade in, measured in seconds.
|
|
164
|
+
|
|
165
|
+
Defaults to `1`.
|
|
166
|
+
]=]
|
|
167
|
+
|
|
168
|
+
--[=[
|
|
169
|
+
@within Shake
|
|
170
|
+
@prop FadeOutTime number
|
|
171
|
+
How long it takes for the shake to fade out, measured in seconds.
|
|
172
|
+
|
|
173
|
+
Defaults to `1`.
|
|
174
|
+
]=]
|
|
175
|
+
|
|
176
|
+
--[=[
|
|
177
|
+
@within Shake
|
|
178
|
+
@prop SustainTime number
|
|
179
|
+
How long it takes for the shake sustains itself after fading in and
|
|
180
|
+
before fading out.
|
|
181
|
+
|
|
182
|
+
To sustain a shake indefinitely, set `Sustain`
|
|
183
|
+
to `true`, and call the `StopSustain()` method to stop the sustain
|
|
184
|
+
and fade out the shake effect.
|
|
185
|
+
|
|
186
|
+
Defaults to `0`.
|
|
187
|
+
]=]
|
|
188
|
+
|
|
189
|
+
--[=[
|
|
190
|
+
@within Shake
|
|
191
|
+
@prop Sustain boolean
|
|
192
|
+
If `true`, the shake will sustain itself indefinitely once it fades
|
|
193
|
+
in. If `StopSustain()` is called, the sustain will end and the shake
|
|
194
|
+
will fade out based on the `FadeOutTime`.
|
|
195
|
+
|
|
196
|
+
Defaults to `false`.
|
|
197
|
+
]=]
|
|
198
|
+
|
|
199
|
+
--[=[
|
|
200
|
+
@within Shake
|
|
201
|
+
@prop PositionInfluence Vector3
|
|
202
|
+
This is similar to `Amplitude` but multiplies against each axis
|
|
203
|
+
of the resultant shake vector, and only affects the position vector.
|
|
204
|
+
|
|
205
|
+
Defaults to `Vector3.one`.
|
|
206
|
+
]=]
|
|
207
|
+
|
|
208
|
+
--[=[
|
|
209
|
+
@within Shake
|
|
210
|
+
@prop RotationInfluence Vector3
|
|
211
|
+
This is similar to `Amplitude` but multiplies against each axis
|
|
212
|
+
of the resultant shake vector, and only affects the rotation vector.
|
|
213
|
+
|
|
214
|
+
Defaults to `Vector3.one`.
|
|
215
|
+
]=]
|
|
216
|
+
|
|
217
|
+
--[=[
|
|
218
|
+
@within Shake
|
|
219
|
+
@prop TimeFunction () -> number
|
|
220
|
+
The function used to get the current time. This defaults to
|
|
221
|
+
`time` during runtime, and `os.clock` otherwise. Usually this
|
|
222
|
+
will not need to be set, but it can be optionally configured
|
|
223
|
+
if desired.
|
|
224
|
+
]=]
|
|
225
|
+
|
|
226
|
+
--[=[
|
|
227
|
+
@return Shake
|
|
228
|
+
Construct a new Shake instance.
|
|
229
|
+
]=]
|
|
230
|
+
function Shake.new(): Shake
|
|
231
|
+
local self = setmetatable({}, Shake)
|
|
232
|
+
|
|
233
|
+
self.Amplitude = 1
|
|
234
|
+
self.Frequency = 1
|
|
235
|
+
self.FadeInTime = 1
|
|
236
|
+
self.FadeOutTime = 1
|
|
237
|
+
self.SustainTime = 0
|
|
238
|
+
self.Sustain = false
|
|
239
|
+
self.PositionInfluence = Vector3.one
|
|
240
|
+
self.RotationInfluence = Vector3.one
|
|
241
|
+
self.TimeFunction = if RunService:IsRunning() then time else os.clock
|
|
242
|
+
|
|
243
|
+
self._timeOffset = rng:NextNumber(-1e6, 1e6)
|
|
244
|
+
self._startTime = 0
|
|
245
|
+
self._running = false
|
|
246
|
+
self._signalConnections = {}
|
|
247
|
+
self._renderBindings = {}
|
|
248
|
+
|
|
249
|
+
return self
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
--[=[
|
|
253
|
+
Apply an inverse square intensity multiplier to the given vector based on the
|
|
254
|
+
distance away from some source. This can be used to simulate shake intensity
|
|
255
|
+
based on the distance the shake is occurring from some source.
|
|
256
|
+
|
|
257
|
+
For instance, if the shake is caused by an explosion in the game, the shake
|
|
258
|
+
can be calculated as such:
|
|
259
|
+
|
|
260
|
+
```lua
|
|
261
|
+
local function Explosion(positionOfExplosion: Vector3)
|
|
262
|
+
|
|
263
|
+
local cam = workspace.CurrentCamera
|
|
264
|
+
local renderPriority = Enum.RenderPriority.Last.Value
|
|
265
|
+
|
|
266
|
+
local shake = Shake.new()
|
|
267
|
+
-- Set shake properties here
|
|
268
|
+
|
|
269
|
+
local function ExplosionShake(pos: Vector3, rot: Vector3)
|
|
270
|
+
local distance = (cam.CFrame.Position - positionOfExplosion).Magnitude
|
|
271
|
+
pos = Shake.InverseSquare(pos, distance)
|
|
272
|
+
rot = Shake.InverseSquare(rot, distance)
|
|
273
|
+
cam.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
shake:BindToRenderStep("ExplosionShake", renderPriority, ExplosionShake)
|
|
277
|
+
|
|
278
|
+
end
|
|
279
|
+
```
|
|
280
|
+
]=]
|
|
281
|
+
function Shake.InverseSquare(shake: Vector3, distance: number): Vector3
|
|
282
|
+
if distance < 1 then
|
|
283
|
+
distance = 1
|
|
284
|
+
end
|
|
285
|
+
local intensity = 1 / (distance * distance)
|
|
286
|
+
return shake * intensity
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
--[=[
|
|
290
|
+
Returns a unique render name for every call, which can
|
|
291
|
+
be used with the `BindToRenderStep` method optionally.
|
|
292
|
+
|
|
293
|
+
```lua
|
|
294
|
+
shake:BindToRenderStep(Shake.NextRenderName(), ...)
|
|
295
|
+
```
|
|
296
|
+
]=]
|
|
297
|
+
function Shake.NextRenderName(): string
|
|
298
|
+
renderId += 1
|
|
299
|
+
return ("__shake_%.4i__"):format(renderId)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
--[=[
|
|
303
|
+
Start the shake effect.
|
|
304
|
+
|
|
305
|
+
:::note
|
|
306
|
+
This **must** be called before calling `Update`. As such, it should also be
|
|
307
|
+
called once before or after calling `OnSignal` or `BindToRenderStep` methods.
|
|
308
|
+
:::
|
|
309
|
+
]=]
|
|
310
|
+
function Shake:Start()
|
|
311
|
+
self._startTime = self.TimeFunction()
|
|
312
|
+
self._running = true
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
--[=[
|
|
316
|
+
Stops the shake effect. If using `OnSignal` or `BindToRenderStep`, those bound
|
|
317
|
+
functions will be disconnected/unbound.
|
|
318
|
+
|
|
319
|
+
`Stop` is automatically called when the shake effect is completed _or_ when the
|
|
320
|
+
`Destroy` method is called.
|
|
321
|
+
]=]
|
|
322
|
+
function Shake:Stop()
|
|
323
|
+
self._running = false
|
|
324
|
+
|
|
325
|
+
for _, name in self._renderBindings do
|
|
326
|
+
RunService:UnbindFromRenderStep(name)
|
|
327
|
+
end
|
|
328
|
+
table.clear(self._renderBindings)
|
|
329
|
+
|
|
330
|
+
for _, conn in self._signalConnections do
|
|
331
|
+
conn:Disconnect()
|
|
332
|
+
end
|
|
333
|
+
table.clear(self._signalConnections)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
--[=[
|
|
337
|
+
Returns `true` if the shake instance is currently running,
|
|
338
|
+
otherwise returns `false`.
|
|
339
|
+
]=]
|
|
340
|
+
function Shake:IsShaking(): boolean
|
|
341
|
+
return self._running
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
--[=[
|
|
345
|
+
Schedules a sustained shake to stop. This works by setting the
|
|
346
|
+
`Sustain` field to `false` and letting the shake effect fade out
|
|
347
|
+
based on the `FadeOutTime` field.
|
|
348
|
+
]=]
|
|
349
|
+
function Shake:StopSustain()
|
|
350
|
+
local now = self.TimeFunction()
|
|
351
|
+
self.Sustain = false
|
|
352
|
+
self.SustainTime = (now - self._startTime) - self.FadeInTime
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
--[=[
|
|
356
|
+
Calculates the current shake vector. This should be continuously
|
|
357
|
+
called inside a loop, such as `RunService.Heartbeat`. Alternatively,
|
|
358
|
+
`OnSignal` or `BindToRenderStep` can be used to automatically call
|
|
359
|
+
this function.
|
|
360
|
+
|
|
361
|
+
Returns a tuple of three values:
|
|
362
|
+
1. `position: Vector3` - Position shake offset
|
|
363
|
+
2. `rotation: Vector3` - Rotation shake offset
|
|
364
|
+
3. `completed: boolean` - Flag indicating if the shake is finished
|
|
365
|
+
|
|
366
|
+
```lua
|
|
367
|
+
local hb
|
|
368
|
+
hb = RunService.Heartbeat:Connect(function()
|
|
369
|
+
local offsetPosition, offsetRotation, isDone = shake:Update()
|
|
370
|
+
if isDone then
|
|
371
|
+
hb:Disconnect()
|
|
372
|
+
end
|
|
373
|
+
-- Use `offsetPosition` and `offsetRotation` here
|
|
374
|
+
end)
|
|
375
|
+
```
|
|
376
|
+
]=]
|
|
377
|
+
function Shake:Update(): (Vector3, Vector3, boolean)
|
|
378
|
+
local done = false
|
|
379
|
+
|
|
380
|
+
local now = self.TimeFunction()
|
|
381
|
+
local dur = now - self._startTime
|
|
382
|
+
|
|
383
|
+
local noiseInput = ((now + self._timeOffset) / self.Frequency) % 10000
|
|
384
|
+
|
|
385
|
+
local multiplierFadeIn = 1
|
|
386
|
+
local multiplierFadeOut = 1
|
|
387
|
+
if dur < self.FadeInTime then
|
|
388
|
+
-- Fade in
|
|
389
|
+
multiplierFadeIn = dur / self.FadeInTime
|
|
390
|
+
end
|
|
391
|
+
if not self.Sustain and dur > self.FadeInTime + self.SustainTime then
|
|
392
|
+
if self.FadeOutTime == 0 then
|
|
393
|
+
done = true
|
|
394
|
+
else
|
|
395
|
+
-- Fade out
|
|
396
|
+
multiplierFadeOut = 1 - (dur - self.FadeInTime - self.SustainTime) / self.FadeOutTime
|
|
397
|
+
if not self.Sustain and dur >= self.FadeInTime + self.SustainTime + self.FadeOutTime then
|
|
398
|
+
done = true
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
local offset = Vector3.new(
|
|
404
|
+
math.noise(noiseInput, 0) / 2,
|
|
405
|
+
math.noise(0, noiseInput) / 2,
|
|
406
|
+
math.noise(noiseInput, noiseInput) / 2
|
|
407
|
+
) * self.Amplitude * math.min(multiplierFadeIn, multiplierFadeOut)
|
|
408
|
+
|
|
409
|
+
if done then
|
|
410
|
+
self:Stop()
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
return self.PositionInfluence * offset, self.RotationInfluence * offset, done
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
--[=[
|
|
417
|
+
@param signal Signal | RBXScriptSignal
|
|
418
|
+
@param callbackFn UpdateCallbackFn
|
|
419
|
+
@return Connection | RBXScriptConnection
|
|
420
|
+
|
|
421
|
+
Bind the `Update` method to a signal. For instance, this can be used
|
|
422
|
+
to connect to `RunService.Heartbeat`.
|
|
423
|
+
|
|
424
|
+
All connections are cleaned up when the shake instance is stopped
|
|
425
|
+
or destroyed.
|
|
426
|
+
|
|
427
|
+
```lua
|
|
428
|
+
local function SomeShake(pos: Vector3, rot: Vector3, completed: boolean)
|
|
429
|
+
-- Shake
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
shake:OnSignal(RunService.Heartbeat, SomeShake)
|
|
433
|
+
```
|
|
434
|
+
]=]
|
|
435
|
+
function Shake:OnSignal(signal, callbackFn: UpdateCallbackFn)
|
|
436
|
+
local conn = signal:Connect(function()
|
|
437
|
+
callbackFn(self:Update())
|
|
438
|
+
end)
|
|
439
|
+
|
|
440
|
+
table.insert(self._signalConnections, conn)
|
|
441
|
+
|
|
442
|
+
return conn
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
--[=[
|
|
446
|
+
@param name string -- Name passed to `RunService:BindToRenderStep`
|
|
447
|
+
@param priority number -- Priority passed to `RunService:BindToRenderStep`
|
|
448
|
+
@param callbackFn UpdateCallbackFn
|
|
449
|
+
|
|
450
|
+
Bind the `Update` method to RenderStep.
|
|
451
|
+
|
|
452
|
+
All bound functions are cleaned up when the shake instance is stopped
|
|
453
|
+
or destroyed.
|
|
454
|
+
|
|
455
|
+
```lua
|
|
456
|
+
local renderPriority = Enum.RenderPriority.Camera.Value
|
|
457
|
+
|
|
458
|
+
local function SomeShake(pos: Vector3, rot: Vector3, completed: boolean)
|
|
459
|
+
-- Shake
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
shake:BindToRenderStep("SomeShake", renderPriority, SomeShake)
|
|
463
|
+
```
|
|
464
|
+
]=]
|
|
465
|
+
function Shake:BindToRenderStep(name: string, priority: number, callbackFn: UpdateCallbackFn)
|
|
466
|
+
RunService:BindToRenderStep(name, priority, function()
|
|
467
|
+
callbackFn(self:Update())
|
|
468
|
+
end)
|
|
469
|
+
|
|
470
|
+
table.insert(self._renderBindings, name)
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
--[=[
|
|
474
|
+
@return Shake
|
|
475
|
+
Creates a new shake with identical properties as
|
|
476
|
+
this one. This does _not_ clone over playing state,
|
|
477
|
+
and thus the cloned instance will be in a stopped
|
|
478
|
+
state.
|
|
479
|
+
|
|
480
|
+
A use-case for using `Clone` would be to create a module
|
|
481
|
+
with a list of shake presets. These presets can be cloned
|
|
482
|
+
when desired for use. For instance, there might be presets
|
|
483
|
+
for explosions, recoil, or earthquakes.
|
|
484
|
+
|
|
485
|
+
```lua
|
|
486
|
+
--------------------------------------
|
|
487
|
+
-- Example preset module
|
|
488
|
+
local ShakePresets = {}
|
|
489
|
+
|
|
490
|
+
local explosion = Shake.new()
|
|
491
|
+
-- Configure `explosion` shake here
|
|
492
|
+
ShakePresets.Explosion = explosion
|
|
493
|
+
|
|
494
|
+
return ShakePresets
|
|
495
|
+
--------------------------------------
|
|
496
|
+
|
|
497
|
+
-- Use the module:
|
|
498
|
+
local ShakePresets = require(somewhere.ShakePresets)
|
|
499
|
+
local explosionShake = ShakePresets.Explosion:Clone()
|
|
500
|
+
```
|
|
501
|
+
]=]
|
|
502
|
+
function Shake:Clone()
|
|
503
|
+
local shake = Shake.new()
|
|
504
|
+
local cloneFields = {
|
|
505
|
+
"Amplitude",
|
|
506
|
+
"Frequency",
|
|
507
|
+
"FadeInTime",
|
|
508
|
+
"FadeOutTime",
|
|
509
|
+
"SustainTime",
|
|
510
|
+
"Sustain",
|
|
511
|
+
"PositionInfluence",
|
|
512
|
+
"RotationInfluence",
|
|
513
|
+
"TimeFunction",
|
|
514
|
+
}
|
|
515
|
+
for _, field in cloneFields do
|
|
516
|
+
shake[field] = self[field]
|
|
517
|
+
end
|
|
518
|
+
return shake
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
--[=[
|
|
522
|
+
Alias for `Stop()`.
|
|
523
|
+
]=]
|
|
524
|
+
function Shake:Destroy()
|
|
525
|
+
self:Stop()
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
new = Shake.new,
|
|
530
|
+
InverseSquare = Shake.InverseSquare,
|
|
531
|
+
NextRenderName = Shake.NextRenderName,
|
|
532
|
+
}
|