roblox-opencode 1.0.0 → 1.0.2
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 +877 -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 +1618 -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,559 +1,559 @@
|
|
|
1
|
-
-- Gamepad
|
|
2
|
-
-- Stephen Leitnick
|
|
3
|
-
-- December 23, 2021
|
|
4
|
-
|
|
5
|
-
local Signal = require(script.Parent.Parent.Signal)
|
|
6
|
-
local Trove = require(script.Parent.Parent.Trove)
|
|
7
|
-
|
|
8
|
-
local GuiService = game:GetService("GuiService")
|
|
9
|
-
local HapticService = game:GetService("HapticService")
|
|
10
|
-
local RunService = game:GetService("RunService")
|
|
11
|
-
local UserInputService = game:GetService("UserInputService")
|
|
12
|
-
|
|
13
|
-
local function ApplyDeadzone(value: number, threshold: number): number
|
|
14
|
-
if math.abs(value) < threshold then
|
|
15
|
-
return 0
|
|
16
|
-
end
|
|
17
|
-
return ((math.abs(value) - threshold) / (1 - threshold)) * math.sign(value)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
local function GetActiveGamepad(): Enum.UserInputType?
|
|
21
|
-
local activeGamepad = nil
|
|
22
|
-
local navGamepads = UserInputService:GetNavigationGamepads()
|
|
23
|
-
if #navGamepads > 1 then
|
|
24
|
-
for _, navGamepad in navGamepads do
|
|
25
|
-
if activeGamepad == nil or navGamepad.Value < activeGamepad.Value then
|
|
26
|
-
activeGamepad = navGamepad
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
else
|
|
30
|
-
local connectedGamepads = UserInputService:GetConnectedGamepads()
|
|
31
|
-
for _, connectedGamepad in connectedGamepads do
|
|
32
|
-
if activeGamepad == nil or connectedGamepad.Value < activeGamepad.Value then
|
|
33
|
-
activeGamepad = connectedGamepad
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
if activeGamepad and not UserInputService:GetGamepadConnected(activeGamepad) then
|
|
38
|
-
activeGamepad = nil
|
|
39
|
-
end
|
|
40
|
-
return activeGamepad
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
local function HeartbeatDelay(duration: number, callback: () -> nil): RBXScriptConnection
|
|
44
|
-
local start = time()
|
|
45
|
-
local connection
|
|
46
|
-
connection = RunService.Heartbeat:Connect(function()
|
|
47
|
-
local elapsed = time() - start
|
|
48
|
-
if elapsed >= duration then
|
|
49
|
-
connection:Disconnect()
|
|
50
|
-
callback()
|
|
51
|
-
end
|
|
52
|
-
end)
|
|
53
|
-
return connection
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
--[=[
|
|
57
|
-
@class Gamepad
|
|
58
|
-
@client
|
|
59
|
-
|
|
60
|
-
The Gamepad class is part of the Input package.
|
|
61
|
-
|
|
62
|
-
```lua
|
|
63
|
-
local Gamepad = require(packages.Input).Gamepad
|
|
64
|
-
|
|
65
|
-
local gamepad = Gamepad.new()
|
|
66
|
-
```
|
|
67
|
-
]=]
|
|
68
|
-
local Gamepad = {}
|
|
69
|
-
Gamepad.__index = Gamepad
|
|
70
|
-
|
|
71
|
-
--[=[
|
|
72
|
-
@within Gamepad
|
|
73
|
-
@prop ButtonDown Signal<(button: Enum.KeyCode, processed: boolean)>
|
|
74
|
-
@readonly
|
|
75
|
-
The ButtonDown signal fires when a gamepad button is pressed
|
|
76
|
-
down. The pressed KeyCode is passed to the signal, along with
|
|
77
|
-
whether or not the event was processed.
|
|
78
|
-
|
|
79
|
-
```lua
|
|
80
|
-
gamepad.ButtonDown:Connect(function(button: Enum.KeyCode, processed: boolean)
|
|
81
|
-
print("Button down", button, processed)
|
|
82
|
-
end)
|
|
83
|
-
```
|
|
84
|
-
]=]
|
|
85
|
-
|
|
86
|
-
--[=[
|
|
87
|
-
@within Gamepad
|
|
88
|
-
@prop ButtonUp Signal<(button: Enum.KeyCode, processed: boolean)>
|
|
89
|
-
@readonly
|
|
90
|
-
The ButtonUp signal fires when a gamepad button is released.
|
|
91
|
-
The released KeyCode is passed to the signal, along with
|
|
92
|
-
whether or not the event was processed.
|
|
93
|
-
|
|
94
|
-
```lua
|
|
95
|
-
gamepad.ButtonUp:Connect(function(button: Enum.KeyCode, processed: boolean)
|
|
96
|
-
print("Button up", button, processed)
|
|
97
|
-
end)
|
|
98
|
-
```
|
|
99
|
-
]=]
|
|
100
|
-
|
|
101
|
-
--[=[
|
|
102
|
-
@within Gamepad
|
|
103
|
-
@prop Connected Signal
|
|
104
|
-
@readonly
|
|
105
|
-
Fires when the gamepad is connected. This will _not_ fire if the
|
|
106
|
-
active gamepad is switched. To detect switching to different
|
|
107
|
-
active gamepads, use the `GamepadChanged` signal.
|
|
108
|
-
|
|
109
|
-
There is also a `gamepad:IsConnected()` method.
|
|
110
|
-
|
|
111
|
-
```lua
|
|
112
|
-
gamepad.Connected:Connect(function()
|
|
113
|
-
print("Connected")
|
|
114
|
-
end)
|
|
115
|
-
```
|
|
116
|
-
]=]
|
|
117
|
-
|
|
118
|
-
--[=[
|
|
119
|
-
@within Gamepad
|
|
120
|
-
@prop Disconnected Signal
|
|
121
|
-
@readonly
|
|
122
|
-
Fires when the gamepad is disconnected. This will _not_ fire if the
|
|
123
|
-
active gamepad is switched. To detect switching to different
|
|
124
|
-
active gamepads, use the `GamepadChanged` signal.
|
|
125
|
-
|
|
126
|
-
There is also a `gamepad:IsConnected()` method.
|
|
127
|
-
|
|
128
|
-
```lua
|
|
129
|
-
gamepad.Disconnected:Connect(function()
|
|
130
|
-
print("Disconnected")
|
|
131
|
-
end)
|
|
132
|
-
```
|
|
133
|
-
]=]
|
|
134
|
-
|
|
135
|
-
--[=[
|
|
136
|
-
@within Gamepad
|
|
137
|
-
@prop GamepadChanged Signal<gamepad: Enum.UserInputType>
|
|
138
|
-
@readonly
|
|
139
|
-
Fires when the active gamepad switches. Internally, the gamepad
|
|
140
|
-
object will always wrap around the active gamepad, so nothing
|
|
141
|
-
needs to be changed.
|
|
142
|
-
|
|
143
|
-
```lua
|
|
144
|
-
gamepad.GamepadChanged:Connect(function(newGamepad: Enum.UserInputType)
|
|
145
|
-
print("Active gamepad changed to:", newGamepad)
|
|
146
|
-
end)
|
|
147
|
-
```
|
|
148
|
-
]=]
|
|
149
|
-
|
|
150
|
-
--[=[
|
|
151
|
-
@within Gamepad
|
|
152
|
-
@prop DefaultDeadzone number
|
|
153
|
-
|
|
154
|
-
:::info Default
|
|
155
|
-
Defaults to `0.05`
|
|
156
|
-
:::
|
|
157
|
-
|
|
158
|
-
The default deadzone used for trigger and thumbstick
|
|
159
|
-
analog readings. It is usually best to set this to
|
|
160
|
-
a small value, or allow players to set this option
|
|
161
|
-
themselves in an in-game settings menu.
|
|
162
|
-
|
|
163
|
-
The `GetThumbstick` and `GetTrigger` methods also allow
|
|
164
|
-
a deadzone value to be passed in, which overrides this
|
|
165
|
-
value.
|
|
166
|
-
]=]
|
|
167
|
-
|
|
168
|
-
--[=[
|
|
169
|
-
@within Gamepad
|
|
170
|
-
@prop SupportsVibration boolean
|
|
171
|
-
@readonly
|
|
172
|
-
Flag to indicate if the currently-active gamepad supports
|
|
173
|
-
haptic motor vibration.
|
|
174
|
-
|
|
175
|
-
It is safe to use the motor methods on the gamepad without
|
|
176
|
-
checking this value, but nothing will happen if the motors
|
|
177
|
-
are not supported.
|
|
178
|
-
]=]
|
|
179
|
-
|
|
180
|
-
--[=[
|
|
181
|
-
@within Gamepad
|
|
182
|
-
@prop State GamepadState
|
|
183
|
-
@readonly
|
|
184
|
-
Maps KeyCodes to the matching InputObjects within the gamepad.
|
|
185
|
-
These can be used to directly read the current input state of
|
|
186
|
-
a given part of the gamepad. For most cases, the given methods
|
|
187
|
-
and properties of `Gamepad` should make use of this table quite
|
|
188
|
-
rare, but it is provided for special use-cases that might occur.
|
|
189
|
-
|
|
190
|
-
:::note Do Not Cache
|
|
191
|
-
These state objects will change if the active gamepad changes.
|
|
192
|
-
Because a player might switch up gamepads during playtime, it cannot
|
|
193
|
-
be assumed that these state objects will always be the same. Thus
|
|
194
|
-
they should be accessed directly from this `State` table anytime they
|
|
195
|
-
need to be used.
|
|
196
|
-
:::
|
|
197
|
-
|
|
198
|
-
```lua
|
|
199
|
-
local leftThumbstick = gamepad.State[Enum.KeyCode.Thumbstick1]
|
|
200
|
-
print(leftThumbstick.Position)
|
|
201
|
-
-- It would be better to use gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1),
|
|
202
|
-
-- but this is just an example of direct state access.
|
|
203
|
-
```
|
|
204
|
-
]=]
|
|
205
|
-
|
|
206
|
-
--[=[
|
|
207
|
-
@within Gamepad
|
|
208
|
-
@type GamepadState {[Enum.KeyCode]: InputObject}
|
|
209
|
-
]=]
|
|
210
|
-
|
|
211
|
-
--[=[
|
|
212
|
-
@param gamepad Enum.UserInputType?
|
|
213
|
-
@return Gamepad
|
|
214
|
-
Constructs a gamepad object.
|
|
215
|
-
|
|
216
|
-
If no gamepad UserInputType is provided, this object will always wrap
|
|
217
|
-
around the currently-active gamepad, even if it changes. In most cases
|
|
218
|
-
where input is needed from just the primary gamepad used by the player,
|
|
219
|
-
leaving the `gamepad` argument blank is preferred.
|
|
220
|
-
|
|
221
|
-
Only include the `gamepad` argument when it is necessary to hard-lock
|
|
222
|
-
the object to a specific gamepad input type.
|
|
223
|
-
|
|
224
|
-
```lua
|
|
225
|
-
-- In most cases, construct the gamepad as such:
|
|
226
|
-
local gamepad = Gamepad.new()
|
|
227
|
-
|
|
228
|
-
-- If the exact UserInputType gamepad is needed, pass it as such:
|
|
229
|
-
local gamepad = Gamepad.new(Enum.UserInputType.Gamepad1)
|
|
230
|
-
```
|
|
231
|
-
]=]
|
|
232
|
-
function Gamepad.new(gamepad: Enum.UserInputType?)
|
|
233
|
-
local self = setmetatable({}, Gamepad)
|
|
234
|
-
|
|
235
|
-
self._trove = Trove.new()
|
|
236
|
-
self._gamepadTrove = self._trove:Construct(Trove)
|
|
237
|
-
self.ButtonDown = self._trove:Construct(Signal)
|
|
238
|
-
self.ButtonUp = self._trove:Construct(Signal)
|
|
239
|
-
self.Connected = self._trove:Construct(Signal)
|
|
240
|
-
self.Disconnected = self._trove:Construct(Signal)
|
|
241
|
-
self.GamepadChanged = self._trove:Construct(Signal)
|
|
242
|
-
self.DefaultDeadzone = 0.05
|
|
243
|
-
self.SupportsVibration = false
|
|
244
|
-
self.State = {}
|
|
245
|
-
|
|
246
|
-
self:_setupGamepad(gamepad)
|
|
247
|
-
self:_setupMotors()
|
|
248
|
-
|
|
249
|
-
return self
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
function Gamepad:_setupActiveGamepad(gamepad: Enum.UserInputType?)
|
|
253
|
-
local lastGamepad = self._gamepad
|
|
254
|
-
if gamepad == lastGamepad then
|
|
255
|
-
return
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
self._gamepadTrove:Clean()
|
|
259
|
-
table.clear(self.State)
|
|
260
|
-
self.SupportsVibration = if gamepad then HapticService:IsVibrationSupported(gamepad) else false
|
|
261
|
-
|
|
262
|
-
self._gamepad = gamepad
|
|
263
|
-
|
|
264
|
-
-- Stop if disconnected:
|
|
265
|
-
if not gamepad then
|
|
266
|
-
self.Disconnected:Fire()
|
|
267
|
-
self.GamepadChanged:Fire(nil)
|
|
268
|
-
return
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
for _, inputObject in UserInputService:GetGamepadState(gamepad) do
|
|
272
|
-
self.State[inputObject.KeyCode] = inputObject
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
self._gamepadTrove:Add(self, "StopMotors")
|
|
276
|
-
|
|
277
|
-
self._gamepadTrove:Connect(UserInputService.InputBegan, function(input, processed)
|
|
278
|
-
if input.UserInputType == gamepad then
|
|
279
|
-
self.ButtonDown:Fire(input.KeyCode, processed)
|
|
280
|
-
end
|
|
281
|
-
end)
|
|
282
|
-
|
|
283
|
-
self._gamepadTrove:Connect(UserInputService.InputEnded, function(input, processed)
|
|
284
|
-
if input.UserInputType == gamepad then
|
|
285
|
-
self.ButtonUp:Fire(input.KeyCode, processed)
|
|
286
|
-
end
|
|
287
|
-
end)
|
|
288
|
-
|
|
289
|
-
if lastGamepad == nil then
|
|
290
|
-
self.Connected:Fire()
|
|
291
|
-
end
|
|
292
|
-
self.GamepadChanged:Fire(gamepad)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
function Gamepad:_setupGamepad(forcedGamepad: Enum.UserInputType?)
|
|
296
|
-
if forcedGamepad then
|
|
297
|
-
-- Forced gamepad:
|
|
298
|
-
|
|
299
|
-
self._trove:Connect(UserInputService.GamepadConnected, function(gp)
|
|
300
|
-
if gp == forcedGamepad then
|
|
301
|
-
self:_setupActiveGamepad(forcedGamepad)
|
|
302
|
-
end
|
|
303
|
-
end)
|
|
304
|
-
|
|
305
|
-
self._trove:Connect(UserInputService.GamepadDisconnected, function(gp)
|
|
306
|
-
if gp == forcedGamepad then
|
|
307
|
-
self:_setupActiveGamepad(nil)
|
|
308
|
-
end
|
|
309
|
-
end)
|
|
310
|
-
|
|
311
|
-
if UserInputService:GetGamepadConnected(forcedGamepad) then
|
|
312
|
-
self:_setupActiveGamepad(forcedGamepad)
|
|
313
|
-
end
|
|
314
|
-
else
|
|
315
|
-
-- Dynamic gamepad:
|
|
316
|
-
|
|
317
|
-
local function CheckToSetupActive()
|
|
318
|
-
local active = GetActiveGamepad()
|
|
319
|
-
if active ~= self._gamepad then
|
|
320
|
-
self:_setupActiveGamepad(active)
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
self._trove:Connect(UserInputService.GamepadConnected, CheckToSetupActive)
|
|
325
|
-
self._trove:Connect(UserInputService.GamepadDisconnected, CheckToSetupActive)
|
|
326
|
-
self:_setupActiveGamepad(GetActiveGamepad())
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
function Gamepad:_setupMotors()
|
|
331
|
-
self._setMotorIds = {}
|
|
332
|
-
for _, motor in Enum.VibrationMotor:GetEnumItems() do
|
|
333
|
-
self._setMotorIds[motor] = 0
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
--[=[
|
|
338
|
-
@param thumbstick Enum.KeyCode
|
|
339
|
-
@param deadzoneThreshold number?
|
|
340
|
-
@return Vector2
|
|
341
|
-
Gets the position of the given thumbstick. The two thumbstick
|
|
342
|
-
KeyCodes are `Enum.KeyCode.Thumbstick1` and `Enum.KeyCode.Thumbstick2`.
|
|
343
|
-
|
|
344
|
-
If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
|
|
345
|
-
used instead.
|
|
346
|
-
|
|
347
|
-
```lua
|
|
348
|
-
local leftThumbstick = gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1)
|
|
349
|
-
print("Left thumbstick position", leftThumbstick)
|
|
350
|
-
```
|
|
351
|
-
]=]
|
|
352
|
-
function Gamepad:GetThumbstick(thumbstick: Enum.KeyCode, deadzoneThreshold: number?): Vector2
|
|
353
|
-
local pos = self.State[thumbstick].Position
|
|
354
|
-
local deadzone = deadzoneThreshold or self.DefaultDeadzone
|
|
355
|
-
return Vector2.new(ApplyDeadzone(pos.X, deadzone), ApplyDeadzone(pos.Y, deadzone))
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
--[=[
|
|
359
|
-
@param trigger KeyCode
|
|
360
|
-
@param deadzoneThreshold number?
|
|
361
|
-
@return number
|
|
362
|
-
Gets the position of the given trigger. The triggers are usually going
|
|
363
|
-
to be `Enum.KeyCode.ButtonL2` and `Enum.KeyCode.ButtonR2`. These trigger
|
|
364
|
-
buttons are analog, and will output a value between the range of [0, 1].
|
|
365
|
-
|
|
366
|
-
If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
|
|
367
|
-
used instead.
|
|
368
|
-
|
|
369
|
-
```lua
|
|
370
|
-
local triggerAmount = gamepad:GetTrigger(Enum.KeyCode.ButtonR2)
|
|
371
|
-
print(triggerAmount)
|
|
372
|
-
```
|
|
373
|
-
]=]
|
|
374
|
-
function Gamepad:GetTrigger(trigger: Enum.KeyCode, deadzoneThreshold: number?): number
|
|
375
|
-
return ApplyDeadzone(self.State[trigger].Position.Z, deadzoneThreshold or self.DefaultDeadzone)
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
--[=[
|
|
379
|
-
@param gamepadButton KeyCode
|
|
380
|
-
@return boolean
|
|
381
|
-
Returns `true` if the given button is down. This includes
|
|
382
|
-
any button on the gamepad, such as `Enum.KeyCode.ButtonA`,
|
|
383
|
-
`Enum.KeyCode.ButtonL3`, `Enum.KeyCode.DPadUp`, etc.
|
|
384
|
-
|
|
385
|
-
```lua
|
|
386
|
-
-- Check if the 'A' button is down:
|
|
387
|
-
if gamepad:IsButtonDown(Enum.KeyCode.ButtonA) then
|
|
388
|
-
print("ButtonA is down")
|
|
389
|
-
end
|
|
390
|
-
```
|
|
391
|
-
]=]
|
|
392
|
-
function Gamepad:IsButtonDown(gamepadButton: Enum.KeyCode): boolean
|
|
393
|
-
return UserInputService:IsGamepadButtonDown(self._gamepad, gamepadButton)
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
--[=[
|
|
397
|
-
@param motor Enum.VibrationMotor
|
|
398
|
-
@return boolean
|
|
399
|
-
Returns `true` if the given motor is supported.
|
|
400
|
-
|
|
401
|
-
```lua
|
|
402
|
-
-- Pulse the trigger (e.g. shooting a weapon), but fall back to
|
|
403
|
-
-- the large motor if not supported:
|
|
404
|
-
local motor = Enum.VibrationMotor.Large
|
|
405
|
-
if gamepad:IsMotorSupported(Enum.VibrationMotor.RightTrigger) then
|
|
406
|
-
motor = Enum.VibrationMotor.RightTrigger
|
|
407
|
-
end
|
|
408
|
-
gamepad:PulseMotor(motor, 1, 0.1)
|
|
409
|
-
```
|
|
410
|
-
]=]
|
|
411
|
-
function Gamepad:IsMotorSupported(motor: Enum.VibrationMotor): boolean
|
|
412
|
-
return HapticService:IsMotorSupported(self._gamepad, motor)
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
--[=[
|
|
416
|
-
@param motor Enum.VibrationMotor
|
|
417
|
-
@param intensity number
|
|
418
|
-
Sets the gamepad's haptic motor to a certain intensity. The
|
|
419
|
-
intensity value is a number in the range of [0, 1].
|
|
420
|
-
|
|
421
|
-
```lua
|
|
422
|
-
gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
|
|
423
|
-
```
|
|
424
|
-
]=]
|
|
425
|
-
function Gamepad:SetMotor(motor: Enum.VibrationMotor, intensity: number): number
|
|
426
|
-
self._setMotorIds[motor] += 1
|
|
427
|
-
local id = self._setMotorIds[motor]
|
|
428
|
-
HapticService:SetMotor(self._gamepad, motor, intensity)
|
|
429
|
-
|
|
430
|
-
return id
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
--[=[
|
|
434
|
-
@param motor Enum.VibrationMotor
|
|
435
|
-
@param intensity number
|
|
436
|
-
@param duration number
|
|
437
|
-
Sets the gamepad's haptic motor to a certain intensity for a given
|
|
438
|
-
period of time. The motor will stop vibrating after the given
|
|
439
|
-
`duration` has elapsed.
|
|
440
|
-
|
|
441
|
-
Calling any motor setter methods (e.g. `SetMotor`, `PulseMotor`,
|
|
442
|
-
`StopMotor`) _after_ calling this method will override the pulse.
|
|
443
|
-
For instance, if `PulseMotor` is called, and then `SetMotor` is
|
|
444
|
-
called right afterwards, `SetMotor` will take precedent.
|
|
445
|
-
|
|
446
|
-
```lua
|
|
447
|
-
-- Pulse the large motor for 0.2 seconds with an intensity of 90%:
|
|
448
|
-
gamepad:PulseMotor(Enum.VibrationMotor.Large, 0.9, 0.2)
|
|
449
|
-
|
|
450
|
-
-- Example of PulseMotor being overridden:
|
|
451
|
-
gamepad:PulseMotor(Enum.VibrationMotor.Large, 1, 3)
|
|
452
|
-
task.wait(0.1)
|
|
453
|
-
gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
|
|
454
|
-
-- Now the pulse won't shut off the motor after 3 seconds,
|
|
455
|
-
-- because SetMotor was called, which cancels the pulse.
|
|
456
|
-
```
|
|
457
|
-
]=]
|
|
458
|
-
function Gamepad:PulseMotor(motor: Enum.VibrationMotor, intensity: number, duration: number)
|
|
459
|
-
local id = self:SetMotor(motor, intensity)
|
|
460
|
-
|
|
461
|
-
local heartbeat = HeartbeatDelay(duration, function()
|
|
462
|
-
if self._setMotorIds[motor] ~= id then
|
|
463
|
-
return
|
|
464
|
-
end
|
|
465
|
-
self:StopMotor(motor)
|
|
466
|
-
end)
|
|
467
|
-
|
|
468
|
-
self._gamepadTrove:Add(heartbeat)
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
--[=[
|
|
472
|
-
@param motor Enum.VibrationMotor
|
|
473
|
-
Stops the given motor. This is equivalent to calling
|
|
474
|
-
`gamepad:SetMotor(motor, 0)`.
|
|
475
|
-
|
|
476
|
-
```lua
|
|
477
|
-
gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
|
|
478
|
-
task.wait(0.1)
|
|
479
|
-
gamepad:StopMotor(Enum.VibrationMotor.Large)
|
|
480
|
-
```
|
|
481
|
-
]=]
|
|
482
|
-
function Gamepad:StopMotor(motor: Enum.VibrationMotor)
|
|
483
|
-
self:SetMotor(motor, 0)
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
--[=[
|
|
487
|
-
Stops all motors on the gamepad.
|
|
488
|
-
|
|
489
|
-
```lua
|
|
490
|
-
gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
|
|
491
|
-
gamepad:SetMotor(Enum.VibrationMotor.Small, 1)
|
|
492
|
-
task.wait(0.1)
|
|
493
|
-
gamepad:StopMotors()
|
|
494
|
-
```
|
|
495
|
-
]=]
|
|
496
|
-
function Gamepad:StopMotors()
|
|
497
|
-
for _, motor in Enum.VibrationMotor:GetEnumItems() do
|
|
498
|
-
if self:IsMotorSupported(motor) then
|
|
499
|
-
self:StopMotor(motor)
|
|
500
|
-
end
|
|
501
|
-
end
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
--[=[
|
|
505
|
-
@return boolean
|
|
506
|
-
Returns `true` if the gamepad is currently connected.
|
|
507
|
-
]=]
|
|
508
|
-
function Gamepad:IsConnected(): boolean
|
|
509
|
-
return if self._gamepad then UserInputService:GetGamepadConnected(self._gamepad) else false
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
--[=[
|
|
513
|
-
@return Enum.UserInputType?
|
|
514
|
-
Gets the current gamepad UserInputType that the gamepad object
|
|
515
|
-
is using. This will be `nil` if there is no connected gamepad.
|
|
516
|
-
]=]
|
|
517
|
-
function Gamepad:GetUserInputType(): Enum.UserInputType?
|
|
518
|
-
return self._gamepad
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
--[=[
|
|
522
|
-
@param enabled boolean
|
|
523
|
-
Sets the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
|
|
524
|
-
property.
|
|
525
|
-
|
|
526
|
-
This sets whether or not the Select button on a gamepad will try to auto-select
|
|
527
|
-
a GUI object on screen. This does _not_ turn on/off GUI gamepad navigation,
|
|
528
|
-
but just the initial selection using the Select button.
|
|
529
|
-
|
|
530
|
-
For UX purposes, it usually is preferred to set this to `false` and then
|
|
531
|
-
manually set the [`GuiService.SelectedObject`](https://developer.roblox.com/en-us/api-reference/property/GuiService/SelectedObject)
|
|
532
|
-
property within code to set the selected object for gamepads.
|
|
533
|
-
|
|
534
|
-
```lua
|
|
535
|
-
gamepad:SetAutoSelectGui(false)
|
|
536
|
-
game:GetService("GuiService").SelectedObject = someGuiObject
|
|
537
|
-
```
|
|
538
|
-
]=]
|
|
539
|
-
function Gamepad:SetAutoSelectGui(enabled: boolean)
|
|
540
|
-
GuiService.AutoSelectGuiEnabled = enabled
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
--[=[
|
|
544
|
-
@return boolean
|
|
545
|
-
Returns the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
|
|
546
|
-
property.
|
|
547
|
-
]=]
|
|
548
|
-
function Gamepad:IsAutoSelectGuiEnabled(): boolean
|
|
549
|
-
return GuiService.AutoSelectGuiEnabled
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
--[=[
|
|
553
|
-
Destroys the gamepad object.
|
|
554
|
-
]=]
|
|
555
|
-
function Gamepad:Destroy()
|
|
556
|
-
self._trove:Destroy()
|
|
557
|
-
end
|
|
558
|
-
|
|
559
|
-
return Gamepad
|
|
1
|
+
-- Gamepad
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- December 23, 2021
|
|
4
|
+
|
|
5
|
+
local Signal = require(script.Parent.Parent.Signal)
|
|
6
|
+
local Trove = require(script.Parent.Parent.Trove)
|
|
7
|
+
|
|
8
|
+
local GuiService = game:GetService("GuiService")
|
|
9
|
+
local HapticService = game:GetService("HapticService")
|
|
10
|
+
local RunService = game:GetService("RunService")
|
|
11
|
+
local UserInputService = game:GetService("UserInputService")
|
|
12
|
+
|
|
13
|
+
local function ApplyDeadzone(value: number, threshold: number): number
|
|
14
|
+
if math.abs(value) < threshold then
|
|
15
|
+
return 0
|
|
16
|
+
end
|
|
17
|
+
return ((math.abs(value) - threshold) / (1 - threshold)) * math.sign(value)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
local function GetActiveGamepad(): Enum.UserInputType?
|
|
21
|
+
local activeGamepad = nil
|
|
22
|
+
local navGamepads = UserInputService:GetNavigationGamepads()
|
|
23
|
+
if #navGamepads > 1 then
|
|
24
|
+
for _, navGamepad in navGamepads do
|
|
25
|
+
if activeGamepad == nil or navGamepad.Value < activeGamepad.Value then
|
|
26
|
+
activeGamepad = navGamepad
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
local connectedGamepads = UserInputService:GetConnectedGamepads()
|
|
31
|
+
for _, connectedGamepad in connectedGamepads do
|
|
32
|
+
if activeGamepad == nil or connectedGamepad.Value < activeGamepad.Value then
|
|
33
|
+
activeGamepad = connectedGamepad
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
if activeGamepad and not UserInputService:GetGamepadConnected(activeGamepad) then
|
|
38
|
+
activeGamepad = nil
|
|
39
|
+
end
|
|
40
|
+
return activeGamepad
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
local function HeartbeatDelay(duration: number, callback: () -> nil): RBXScriptConnection
|
|
44
|
+
local start = time()
|
|
45
|
+
local connection
|
|
46
|
+
connection = RunService.Heartbeat:Connect(function()
|
|
47
|
+
local elapsed = time() - start
|
|
48
|
+
if elapsed >= duration then
|
|
49
|
+
connection:Disconnect()
|
|
50
|
+
callback()
|
|
51
|
+
end
|
|
52
|
+
end)
|
|
53
|
+
return connection
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
--[=[
|
|
57
|
+
@class Gamepad
|
|
58
|
+
@client
|
|
59
|
+
|
|
60
|
+
The Gamepad class is part of the Input package.
|
|
61
|
+
|
|
62
|
+
```lua
|
|
63
|
+
local Gamepad = require(packages.Input).Gamepad
|
|
64
|
+
|
|
65
|
+
local gamepad = Gamepad.new()
|
|
66
|
+
```
|
|
67
|
+
]=]
|
|
68
|
+
local Gamepad = {}
|
|
69
|
+
Gamepad.__index = Gamepad
|
|
70
|
+
|
|
71
|
+
--[=[
|
|
72
|
+
@within Gamepad
|
|
73
|
+
@prop ButtonDown Signal<(button: Enum.KeyCode, processed: boolean)>
|
|
74
|
+
@readonly
|
|
75
|
+
The ButtonDown signal fires when a gamepad button is pressed
|
|
76
|
+
down. The pressed KeyCode is passed to the signal, along with
|
|
77
|
+
whether or not the event was processed.
|
|
78
|
+
|
|
79
|
+
```lua
|
|
80
|
+
gamepad.ButtonDown:Connect(function(button: Enum.KeyCode, processed: boolean)
|
|
81
|
+
print("Button down", button, processed)
|
|
82
|
+
end)
|
|
83
|
+
```
|
|
84
|
+
]=]
|
|
85
|
+
|
|
86
|
+
--[=[
|
|
87
|
+
@within Gamepad
|
|
88
|
+
@prop ButtonUp Signal<(button: Enum.KeyCode, processed: boolean)>
|
|
89
|
+
@readonly
|
|
90
|
+
The ButtonUp signal fires when a gamepad button is released.
|
|
91
|
+
The released KeyCode is passed to the signal, along with
|
|
92
|
+
whether or not the event was processed.
|
|
93
|
+
|
|
94
|
+
```lua
|
|
95
|
+
gamepad.ButtonUp:Connect(function(button: Enum.KeyCode, processed: boolean)
|
|
96
|
+
print("Button up", button, processed)
|
|
97
|
+
end)
|
|
98
|
+
```
|
|
99
|
+
]=]
|
|
100
|
+
|
|
101
|
+
--[=[
|
|
102
|
+
@within Gamepad
|
|
103
|
+
@prop Connected Signal
|
|
104
|
+
@readonly
|
|
105
|
+
Fires when the gamepad is connected. This will _not_ fire if the
|
|
106
|
+
active gamepad is switched. To detect switching to different
|
|
107
|
+
active gamepads, use the `GamepadChanged` signal.
|
|
108
|
+
|
|
109
|
+
There is also a `gamepad:IsConnected()` method.
|
|
110
|
+
|
|
111
|
+
```lua
|
|
112
|
+
gamepad.Connected:Connect(function()
|
|
113
|
+
print("Connected")
|
|
114
|
+
end)
|
|
115
|
+
```
|
|
116
|
+
]=]
|
|
117
|
+
|
|
118
|
+
--[=[
|
|
119
|
+
@within Gamepad
|
|
120
|
+
@prop Disconnected Signal
|
|
121
|
+
@readonly
|
|
122
|
+
Fires when the gamepad is disconnected. This will _not_ fire if the
|
|
123
|
+
active gamepad is switched. To detect switching to different
|
|
124
|
+
active gamepads, use the `GamepadChanged` signal.
|
|
125
|
+
|
|
126
|
+
There is also a `gamepad:IsConnected()` method.
|
|
127
|
+
|
|
128
|
+
```lua
|
|
129
|
+
gamepad.Disconnected:Connect(function()
|
|
130
|
+
print("Disconnected")
|
|
131
|
+
end)
|
|
132
|
+
```
|
|
133
|
+
]=]
|
|
134
|
+
|
|
135
|
+
--[=[
|
|
136
|
+
@within Gamepad
|
|
137
|
+
@prop GamepadChanged Signal<gamepad: Enum.UserInputType>
|
|
138
|
+
@readonly
|
|
139
|
+
Fires when the active gamepad switches. Internally, the gamepad
|
|
140
|
+
object will always wrap around the active gamepad, so nothing
|
|
141
|
+
needs to be changed.
|
|
142
|
+
|
|
143
|
+
```lua
|
|
144
|
+
gamepad.GamepadChanged:Connect(function(newGamepad: Enum.UserInputType)
|
|
145
|
+
print("Active gamepad changed to:", newGamepad)
|
|
146
|
+
end)
|
|
147
|
+
```
|
|
148
|
+
]=]
|
|
149
|
+
|
|
150
|
+
--[=[
|
|
151
|
+
@within Gamepad
|
|
152
|
+
@prop DefaultDeadzone number
|
|
153
|
+
|
|
154
|
+
:::info Default
|
|
155
|
+
Defaults to `0.05`
|
|
156
|
+
:::
|
|
157
|
+
|
|
158
|
+
The default deadzone used for trigger and thumbstick
|
|
159
|
+
analog readings. It is usually best to set this to
|
|
160
|
+
a small value, or allow players to set this option
|
|
161
|
+
themselves in an in-game settings menu.
|
|
162
|
+
|
|
163
|
+
The `GetThumbstick` and `GetTrigger` methods also allow
|
|
164
|
+
a deadzone value to be passed in, which overrides this
|
|
165
|
+
value.
|
|
166
|
+
]=]
|
|
167
|
+
|
|
168
|
+
--[=[
|
|
169
|
+
@within Gamepad
|
|
170
|
+
@prop SupportsVibration boolean
|
|
171
|
+
@readonly
|
|
172
|
+
Flag to indicate if the currently-active gamepad supports
|
|
173
|
+
haptic motor vibration.
|
|
174
|
+
|
|
175
|
+
It is safe to use the motor methods on the gamepad without
|
|
176
|
+
checking this value, but nothing will happen if the motors
|
|
177
|
+
are not supported.
|
|
178
|
+
]=]
|
|
179
|
+
|
|
180
|
+
--[=[
|
|
181
|
+
@within Gamepad
|
|
182
|
+
@prop State GamepadState
|
|
183
|
+
@readonly
|
|
184
|
+
Maps KeyCodes to the matching InputObjects within the gamepad.
|
|
185
|
+
These can be used to directly read the current input state of
|
|
186
|
+
a given part of the gamepad. For most cases, the given methods
|
|
187
|
+
and properties of `Gamepad` should make use of this table quite
|
|
188
|
+
rare, but it is provided for special use-cases that might occur.
|
|
189
|
+
|
|
190
|
+
:::note Do Not Cache
|
|
191
|
+
These state objects will change if the active gamepad changes.
|
|
192
|
+
Because a player might switch up gamepads during playtime, it cannot
|
|
193
|
+
be assumed that these state objects will always be the same. Thus
|
|
194
|
+
they should be accessed directly from this `State` table anytime they
|
|
195
|
+
need to be used.
|
|
196
|
+
:::
|
|
197
|
+
|
|
198
|
+
```lua
|
|
199
|
+
local leftThumbstick = gamepad.State[Enum.KeyCode.Thumbstick1]
|
|
200
|
+
print(leftThumbstick.Position)
|
|
201
|
+
-- It would be better to use gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1),
|
|
202
|
+
-- but this is just an example of direct state access.
|
|
203
|
+
```
|
|
204
|
+
]=]
|
|
205
|
+
|
|
206
|
+
--[=[
|
|
207
|
+
@within Gamepad
|
|
208
|
+
@type GamepadState {[Enum.KeyCode]: InputObject}
|
|
209
|
+
]=]
|
|
210
|
+
|
|
211
|
+
--[=[
|
|
212
|
+
@param gamepad Enum.UserInputType?
|
|
213
|
+
@return Gamepad
|
|
214
|
+
Constructs a gamepad object.
|
|
215
|
+
|
|
216
|
+
If no gamepad UserInputType is provided, this object will always wrap
|
|
217
|
+
around the currently-active gamepad, even if it changes. In most cases
|
|
218
|
+
where input is needed from just the primary gamepad used by the player,
|
|
219
|
+
leaving the `gamepad` argument blank is preferred.
|
|
220
|
+
|
|
221
|
+
Only include the `gamepad` argument when it is necessary to hard-lock
|
|
222
|
+
the object to a specific gamepad input type.
|
|
223
|
+
|
|
224
|
+
```lua
|
|
225
|
+
-- In most cases, construct the gamepad as such:
|
|
226
|
+
local gamepad = Gamepad.new()
|
|
227
|
+
|
|
228
|
+
-- If the exact UserInputType gamepad is needed, pass it as such:
|
|
229
|
+
local gamepad = Gamepad.new(Enum.UserInputType.Gamepad1)
|
|
230
|
+
```
|
|
231
|
+
]=]
|
|
232
|
+
function Gamepad.new(gamepad: Enum.UserInputType?)
|
|
233
|
+
local self = setmetatable({}, Gamepad)
|
|
234
|
+
|
|
235
|
+
self._trove = Trove.new()
|
|
236
|
+
self._gamepadTrove = self._trove:Construct(Trove)
|
|
237
|
+
self.ButtonDown = self._trove:Construct(Signal)
|
|
238
|
+
self.ButtonUp = self._trove:Construct(Signal)
|
|
239
|
+
self.Connected = self._trove:Construct(Signal)
|
|
240
|
+
self.Disconnected = self._trove:Construct(Signal)
|
|
241
|
+
self.GamepadChanged = self._trove:Construct(Signal)
|
|
242
|
+
self.DefaultDeadzone = 0.05
|
|
243
|
+
self.SupportsVibration = false
|
|
244
|
+
self.State = {}
|
|
245
|
+
|
|
246
|
+
self:_setupGamepad(gamepad)
|
|
247
|
+
self:_setupMotors()
|
|
248
|
+
|
|
249
|
+
return self
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
function Gamepad:_setupActiveGamepad(gamepad: Enum.UserInputType?)
|
|
253
|
+
local lastGamepad = self._gamepad
|
|
254
|
+
if gamepad == lastGamepad then
|
|
255
|
+
return
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
self._gamepadTrove:Clean()
|
|
259
|
+
table.clear(self.State)
|
|
260
|
+
self.SupportsVibration = if gamepad then HapticService:IsVibrationSupported(gamepad) else false
|
|
261
|
+
|
|
262
|
+
self._gamepad = gamepad
|
|
263
|
+
|
|
264
|
+
-- Stop if disconnected:
|
|
265
|
+
if not gamepad then
|
|
266
|
+
self.Disconnected:Fire()
|
|
267
|
+
self.GamepadChanged:Fire(nil)
|
|
268
|
+
return
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
for _, inputObject in UserInputService:GetGamepadState(gamepad) do
|
|
272
|
+
self.State[inputObject.KeyCode] = inputObject
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
self._gamepadTrove:Add(self, "StopMotors")
|
|
276
|
+
|
|
277
|
+
self._gamepadTrove:Connect(UserInputService.InputBegan, function(input, processed)
|
|
278
|
+
if input.UserInputType == gamepad then
|
|
279
|
+
self.ButtonDown:Fire(input.KeyCode, processed)
|
|
280
|
+
end
|
|
281
|
+
end)
|
|
282
|
+
|
|
283
|
+
self._gamepadTrove:Connect(UserInputService.InputEnded, function(input, processed)
|
|
284
|
+
if input.UserInputType == gamepad then
|
|
285
|
+
self.ButtonUp:Fire(input.KeyCode, processed)
|
|
286
|
+
end
|
|
287
|
+
end)
|
|
288
|
+
|
|
289
|
+
if lastGamepad == nil then
|
|
290
|
+
self.Connected:Fire()
|
|
291
|
+
end
|
|
292
|
+
self.GamepadChanged:Fire(gamepad)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
function Gamepad:_setupGamepad(forcedGamepad: Enum.UserInputType?)
|
|
296
|
+
if forcedGamepad then
|
|
297
|
+
-- Forced gamepad:
|
|
298
|
+
|
|
299
|
+
self._trove:Connect(UserInputService.GamepadConnected, function(gp)
|
|
300
|
+
if gp == forcedGamepad then
|
|
301
|
+
self:_setupActiveGamepad(forcedGamepad)
|
|
302
|
+
end
|
|
303
|
+
end)
|
|
304
|
+
|
|
305
|
+
self._trove:Connect(UserInputService.GamepadDisconnected, function(gp)
|
|
306
|
+
if gp == forcedGamepad then
|
|
307
|
+
self:_setupActiveGamepad(nil)
|
|
308
|
+
end
|
|
309
|
+
end)
|
|
310
|
+
|
|
311
|
+
if UserInputService:GetGamepadConnected(forcedGamepad) then
|
|
312
|
+
self:_setupActiveGamepad(forcedGamepad)
|
|
313
|
+
end
|
|
314
|
+
else
|
|
315
|
+
-- Dynamic gamepad:
|
|
316
|
+
|
|
317
|
+
local function CheckToSetupActive()
|
|
318
|
+
local active = GetActiveGamepad()
|
|
319
|
+
if active ~= self._gamepad then
|
|
320
|
+
self:_setupActiveGamepad(active)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
self._trove:Connect(UserInputService.GamepadConnected, CheckToSetupActive)
|
|
325
|
+
self._trove:Connect(UserInputService.GamepadDisconnected, CheckToSetupActive)
|
|
326
|
+
self:_setupActiveGamepad(GetActiveGamepad())
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
function Gamepad:_setupMotors()
|
|
331
|
+
self._setMotorIds = {}
|
|
332
|
+
for _, motor in Enum.VibrationMotor:GetEnumItems() do
|
|
333
|
+
self._setMotorIds[motor] = 0
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
--[=[
|
|
338
|
+
@param thumbstick Enum.KeyCode
|
|
339
|
+
@param deadzoneThreshold number?
|
|
340
|
+
@return Vector2
|
|
341
|
+
Gets the position of the given thumbstick. The two thumbstick
|
|
342
|
+
KeyCodes are `Enum.KeyCode.Thumbstick1` and `Enum.KeyCode.Thumbstick2`.
|
|
343
|
+
|
|
344
|
+
If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
|
|
345
|
+
used instead.
|
|
346
|
+
|
|
347
|
+
```lua
|
|
348
|
+
local leftThumbstick = gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1)
|
|
349
|
+
print("Left thumbstick position", leftThumbstick)
|
|
350
|
+
```
|
|
351
|
+
]=]
|
|
352
|
+
function Gamepad:GetThumbstick(thumbstick: Enum.KeyCode, deadzoneThreshold: number?): Vector2
|
|
353
|
+
local pos = self.State[thumbstick].Position
|
|
354
|
+
local deadzone = deadzoneThreshold or self.DefaultDeadzone
|
|
355
|
+
return Vector2.new(ApplyDeadzone(pos.X, deadzone), ApplyDeadzone(pos.Y, deadzone))
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
--[=[
|
|
359
|
+
@param trigger KeyCode
|
|
360
|
+
@param deadzoneThreshold number?
|
|
361
|
+
@return number
|
|
362
|
+
Gets the position of the given trigger. The triggers are usually going
|
|
363
|
+
to be `Enum.KeyCode.ButtonL2` and `Enum.KeyCode.ButtonR2`. These trigger
|
|
364
|
+
buttons are analog, and will output a value between the range of [0, 1].
|
|
365
|
+
|
|
366
|
+
If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
|
|
367
|
+
used instead.
|
|
368
|
+
|
|
369
|
+
```lua
|
|
370
|
+
local triggerAmount = gamepad:GetTrigger(Enum.KeyCode.ButtonR2)
|
|
371
|
+
print(triggerAmount)
|
|
372
|
+
```
|
|
373
|
+
]=]
|
|
374
|
+
function Gamepad:GetTrigger(trigger: Enum.KeyCode, deadzoneThreshold: number?): number
|
|
375
|
+
return ApplyDeadzone(self.State[trigger].Position.Z, deadzoneThreshold or self.DefaultDeadzone)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
--[=[
|
|
379
|
+
@param gamepadButton KeyCode
|
|
380
|
+
@return boolean
|
|
381
|
+
Returns `true` if the given button is down. This includes
|
|
382
|
+
any button on the gamepad, such as `Enum.KeyCode.ButtonA`,
|
|
383
|
+
`Enum.KeyCode.ButtonL3`, `Enum.KeyCode.DPadUp`, etc.
|
|
384
|
+
|
|
385
|
+
```lua
|
|
386
|
+
-- Check if the 'A' button is down:
|
|
387
|
+
if gamepad:IsButtonDown(Enum.KeyCode.ButtonA) then
|
|
388
|
+
print("ButtonA is down")
|
|
389
|
+
end
|
|
390
|
+
```
|
|
391
|
+
]=]
|
|
392
|
+
function Gamepad:IsButtonDown(gamepadButton: Enum.KeyCode): boolean
|
|
393
|
+
return UserInputService:IsGamepadButtonDown(self._gamepad, gamepadButton)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
--[=[
|
|
397
|
+
@param motor Enum.VibrationMotor
|
|
398
|
+
@return boolean
|
|
399
|
+
Returns `true` if the given motor is supported.
|
|
400
|
+
|
|
401
|
+
```lua
|
|
402
|
+
-- Pulse the trigger (e.g. shooting a weapon), but fall back to
|
|
403
|
+
-- the large motor if not supported:
|
|
404
|
+
local motor = Enum.VibrationMotor.Large
|
|
405
|
+
if gamepad:IsMotorSupported(Enum.VibrationMotor.RightTrigger) then
|
|
406
|
+
motor = Enum.VibrationMotor.RightTrigger
|
|
407
|
+
end
|
|
408
|
+
gamepad:PulseMotor(motor, 1, 0.1)
|
|
409
|
+
```
|
|
410
|
+
]=]
|
|
411
|
+
function Gamepad:IsMotorSupported(motor: Enum.VibrationMotor): boolean
|
|
412
|
+
return HapticService:IsMotorSupported(self._gamepad, motor)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
--[=[
|
|
416
|
+
@param motor Enum.VibrationMotor
|
|
417
|
+
@param intensity number
|
|
418
|
+
Sets the gamepad's haptic motor to a certain intensity. The
|
|
419
|
+
intensity value is a number in the range of [0, 1].
|
|
420
|
+
|
|
421
|
+
```lua
|
|
422
|
+
gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
|
|
423
|
+
```
|
|
424
|
+
]=]
|
|
425
|
+
function Gamepad:SetMotor(motor: Enum.VibrationMotor, intensity: number): number
|
|
426
|
+
self._setMotorIds[motor] += 1
|
|
427
|
+
local id = self._setMotorIds[motor]
|
|
428
|
+
HapticService:SetMotor(self._gamepad, motor, intensity)
|
|
429
|
+
|
|
430
|
+
return id
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
--[=[
|
|
434
|
+
@param motor Enum.VibrationMotor
|
|
435
|
+
@param intensity number
|
|
436
|
+
@param duration number
|
|
437
|
+
Sets the gamepad's haptic motor to a certain intensity for a given
|
|
438
|
+
period of time. The motor will stop vibrating after the given
|
|
439
|
+
`duration` has elapsed.
|
|
440
|
+
|
|
441
|
+
Calling any motor setter methods (e.g. `SetMotor`, `PulseMotor`,
|
|
442
|
+
`StopMotor`) _after_ calling this method will override the pulse.
|
|
443
|
+
For instance, if `PulseMotor` is called, and then `SetMotor` is
|
|
444
|
+
called right afterwards, `SetMotor` will take precedent.
|
|
445
|
+
|
|
446
|
+
```lua
|
|
447
|
+
-- Pulse the large motor for 0.2 seconds with an intensity of 90%:
|
|
448
|
+
gamepad:PulseMotor(Enum.VibrationMotor.Large, 0.9, 0.2)
|
|
449
|
+
|
|
450
|
+
-- Example of PulseMotor being overridden:
|
|
451
|
+
gamepad:PulseMotor(Enum.VibrationMotor.Large, 1, 3)
|
|
452
|
+
task.wait(0.1)
|
|
453
|
+
gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
|
|
454
|
+
-- Now the pulse won't shut off the motor after 3 seconds,
|
|
455
|
+
-- because SetMotor was called, which cancels the pulse.
|
|
456
|
+
```
|
|
457
|
+
]=]
|
|
458
|
+
function Gamepad:PulseMotor(motor: Enum.VibrationMotor, intensity: number, duration: number)
|
|
459
|
+
local id = self:SetMotor(motor, intensity)
|
|
460
|
+
|
|
461
|
+
local heartbeat = HeartbeatDelay(duration, function()
|
|
462
|
+
if self._setMotorIds[motor] ~= id then
|
|
463
|
+
return
|
|
464
|
+
end
|
|
465
|
+
self:StopMotor(motor)
|
|
466
|
+
end)
|
|
467
|
+
|
|
468
|
+
self._gamepadTrove:Add(heartbeat)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
--[=[
|
|
472
|
+
@param motor Enum.VibrationMotor
|
|
473
|
+
Stops the given motor. This is equivalent to calling
|
|
474
|
+
`gamepad:SetMotor(motor, 0)`.
|
|
475
|
+
|
|
476
|
+
```lua
|
|
477
|
+
gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
|
|
478
|
+
task.wait(0.1)
|
|
479
|
+
gamepad:StopMotor(Enum.VibrationMotor.Large)
|
|
480
|
+
```
|
|
481
|
+
]=]
|
|
482
|
+
function Gamepad:StopMotor(motor: Enum.VibrationMotor)
|
|
483
|
+
self:SetMotor(motor, 0)
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
--[=[
|
|
487
|
+
Stops all motors on the gamepad.
|
|
488
|
+
|
|
489
|
+
```lua
|
|
490
|
+
gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
|
|
491
|
+
gamepad:SetMotor(Enum.VibrationMotor.Small, 1)
|
|
492
|
+
task.wait(0.1)
|
|
493
|
+
gamepad:StopMotors()
|
|
494
|
+
```
|
|
495
|
+
]=]
|
|
496
|
+
function Gamepad:StopMotors()
|
|
497
|
+
for _, motor in Enum.VibrationMotor:GetEnumItems() do
|
|
498
|
+
if self:IsMotorSupported(motor) then
|
|
499
|
+
self:StopMotor(motor)
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
--[=[
|
|
505
|
+
@return boolean
|
|
506
|
+
Returns `true` if the gamepad is currently connected.
|
|
507
|
+
]=]
|
|
508
|
+
function Gamepad:IsConnected(): boolean
|
|
509
|
+
return if self._gamepad then UserInputService:GetGamepadConnected(self._gamepad) else false
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
--[=[
|
|
513
|
+
@return Enum.UserInputType?
|
|
514
|
+
Gets the current gamepad UserInputType that the gamepad object
|
|
515
|
+
is using. This will be `nil` if there is no connected gamepad.
|
|
516
|
+
]=]
|
|
517
|
+
function Gamepad:GetUserInputType(): Enum.UserInputType?
|
|
518
|
+
return self._gamepad
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
--[=[
|
|
522
|
+
@param enabled boolean
|
|
523
|
+
Sets the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
|
|
524
|
+
property.
|
|
525
|
+
|
|
526
|
+
This sets whether or not the Select button on a gamepad will try to auto-select
|
|
527
|
+
a GUI object on screen. This does _not_ turn on/off GUI gamepad navigation,
|
|
528
|
+
but just the initial selection using the Select button.
|
|
529
|
+
|
|
530
|
+
For UX purposes, it usually is preferred to set this to `false` and then
|
|
531
|
+
manually set the [`GuiService.SelectedObject`](https://developer.roblox.com/en-us/api-reference/property/GuiService/SelectedObject)
|
|
532
|
+
property within code to set the selected object for gamepads.
|
|
533
|
+
|
|
534
|
+
```lua
|
|
535
|
+
gamepad:SetAutoSelectGui(false)
|
|
536
|
+
game:GetService("GuiService").SelectedObject = someGuiObject
|
|
537
|
+
```
|
|
538
|
+
]=]
|
|
539
|
+
function Gamepad:SetAutoSelectGui(enabled: boolean)
|
|
540
|
+
GuiService.AutoSelectGuiEnabled = enabled
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
--[=[
|
|
544
|
+
@return boolean
|
|
545
|
+
Returns the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
|
|
546
|
+
property.
|
|
547
|
+
]=]
|
|
548
|
+
function Gamepad:IsAutoSelectGuiEnabled(): boolean
|
|
549
|
+
return GuiService.AutoSelectGuiEnabled
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
--[=[
|
|
553
|
+
Destroys the gamepad object.
|
|
554
|
+
]=]
|
|
555
|
+
function Gamepad:Destroy()
|
|
556
|
+
self._trove:Destroy()
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
return Gamepad
|