@rbxts/axis 0.2.3-v.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/LICENSE +21 -0
- package/README.md +3 -0
- package/out/getInputDevice.luau +27 -0
- package/out/index.d.ts +49 -0
- package/out/init.luau +63 -0
- package/out/input.luau +337 -0
- package/out/match.luau +25 -0
- package/out/types.luau +46 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 teakzc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
18
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
19
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
20
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
|
21
|
+
OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
local match = require(script.Parent.match)
|
|
2
|
+
local types = require(script.Parent.types)
|
|
3
|
+
local previousInputDevice = "Desktop"
|
|
4
|
+
|
|
5
|
+
local function getInputDevice(input: Enum.UserInputType): types.DeviceType
|
|
6
|
+
local result = match(input.Name) {
|
|
7
|
+
"Gamepad1", "Gamepad",
|
|
8
|
+
"Gamepad2", "Gamepad",
|
|
9
|
+
"Gamepad3", "Gamepad",
|
|
10
|
+
"Gamepad4", "Gamepad",
|
|
11
|
+
"Gamepad5", "Gamepad",
|
|
12
|
+
"Gamepad6", "Gamepad",
|
|
13
|
+
"Gamepad7", "Gamepad",
|
|
14
|
+
"Gamepad8", "Gamepad",
|
|
15
|
+
"Touch", "Touch",
|
|
16
|
+
"MouseButton1", "Desktop",
|
|
17
|
+
"MouseButton2", "Desktop",
|
|
18
|
+
"MouseButton3", "Desktop",
|
|
19
|
+
"MouseMovement", "Desktop",
|
|
20
|
+
"MouseWheel", "Desktop",
|
|
21
|
+
"Keyboard", "Desktop"
|
|
22
|
+
}
|
|
23
|
+
previousInputDevice = result or previousInputDevice
|
|
24
|
+
return previousInputDevice
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return getInputDevice
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export namespace Axis {
|
|
2
|
+
/**
|
|
3
|
+
* @within Axis
|
|
4
|
+
* @type DeviceType "Desktop" | "Touch" | "Controller"
|
|
5
|
+
*/
|
|
6
|
+
type DeviceType = "Desktop" | "Touch" | "Controller";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @within Axis
|
|
10
|
+
* @type Map<T> { [Enum | string]: T } & { Enum.KeyCode | Enum.UserInputType }
|
|
11
|
+
*/
|
|
12
|
+
type _Map = Map<defined, defined>; //Map<Enum | string, T> & Array<Enum.KeyCode | Enum.UserInputType>;
|
|
13
|
+
|
|
14
|
+
interface Input<T> {
|
|
15
|
+
read: (controller?: number) => LuaTuple<[T, T]>;
|
|
16
|
+
pressing: (controller?: number) => boolean;
|
|
17
|
+
pressed: (controller?: number) => boolean;
|
|
18
|
+
released: (controller?: number) => boolean;
|
|
19
|
+
changed: (controller?: number) => boolean;
|
|
20
|
+
hold: (value: T, controller?: number) => void;
|
|
21
|
+
move: (value: T, controller?: number) => void;
|
|
22
|
+
map: (keyMap: _Map) => void;
|
|
23
|
+
update: () => void;
|
|
24
|
+
|
|
25
|
+
deadzone?: number;
|
|
26
|
+
vector: boolean;
|
|
27
|
+
current: T[];
|
|
28
|
+
previous: T[];
|
|
29
|
+
active: Array<Map<defined, T>>;
|
|
30
|
+
resets: Map<defined, defined>;
|
|
31
|
+
connections: RBXScriptConnection[];
|
|
32
|
+
keyMap: _Map;
|
|
33
|
+
inputMap: Map<Enum.KeyCode | Enum.UserInputType, T>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type InputConstructor = <T>(input: _Map | (_Map & { deadzone?: number })) => Input<T>;
|
|
37
|
+
|
|
38
|
+
interface Axis {
|
|
39
|
+
device: (inputType: Enum.UserInputType | undefined) => DeviceType;
|
|
40
|
+
update: (inputs: Map<defined, Input<defined>>) => void;
|
|
41
|
+
input: InputConstructor;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function input<T>(inputMap: (_Map & { deadzone?: number }) | _Map): Input<T>;
|
|
45
|
+
|
|
46
|
+
function update(inputs: Map<defined, Input<defined>>): void;
|
|
47
|
+
|
|
48
|
+
function device(input?: Enum.UserInputType): DeviceType;
|
|
49
|
+
}
|
package/out/init.luau
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
local UserInputService = game:GetService("UserInputService")
|
|
2
|
+
local types = require(script.types)
|
|
3
|
+
local constructor = require(script.input)
|
|
4
|
+
local getInputDevice = require(script.getInputDevice)
|
|
5
|
+
|
|
6
|
+
--[=[
|
|
7
|
+
@class Axis
|
|
8
|
+
The Axis library used to define input axes, get devices, and update inputs
|
|
9
|
+
]=]
|
|
10
|
+
--[=[
|
|
11
|
+
@within Axis
|
|
12
|
+
@function input
|
|
13
|
+
@param keyMap Map<T>
|
|
14
|
+
@return Input<T>
|
|
15
|
+
Creates a new input axis with the provided keymap
|
|
16
|
+
```lua
|
|
17
|
+
local attack = Axis.input {
|
|
18
|
+
Enum.KeyCode.E,
|
|
19
|
+
Enum.KeyCode.ButtonX,
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
]=]
|
|
23
|
+
local Axis = {
|
|
24
|
+
input = constructor,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
--[=[
|
|
28
|
+
@within Axis
|
|
29
|
+
@function update
|
|
30
|
+
Updates all the provided inputs as a shorthand
|
|
31
|
+
```lua
|
|
32
|
+
Axis.update(inputMap)
|
|
33
|
+
```
|
|
34
|
+
]=]
|
|
35
|
+
function Axis.update(inputs: { [any]: types.Input<any> })
|
|
36
|
+
for _, input in inputs do
|
|
37
|
+
input:update()
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
--[=[
|
|
42
|
+
@within Axis
|
|
43
|
+
@function device
|
|
44
|
+
@param input Enum.UserInputType?
|
|
45
|
+
@return DeviceType
|
|
46
|
+
Gets the device of the provided UserInputType (or the last UserInputType if none is provided)
|
|
47
|
+
```lua
|
|
48
|
+
local device = Axis.device() --gets device of last input
|
|
49
|
+
if device == "Desktop" then
|
|
50
|
+
print("yay")
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
]=]
|
|
54
|
+
function Axis.device(input: Enum.UserInputType?): types.DeviceType
|
|
55
|
+
return getInputDevice(input or UserInputService:GetLastInputType())
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
export type DeviceType = types.DeviceType
|
|
59
|
+
export type Map<T> = types.Map<T>
|
|
60
|
+
export type Input<T> = types.Input<T>
|
|
61
|
+
export type Axis = types.Axis
|
|
62
|
+
|
|
63
|
+
return Axis :: types.Axis
|
package/out/input.luau
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
--[=[
|
|
4
|
+
@class Input
|
|
5
|
+
The Input class used to define input axes
|
|
6
|
+
]=]
|
|
7
|
+
local UserInputService = game:GetService("UserInputService")
|
|
8
|
+
|
|
9
|
+
local types = require(script.Parent.types)
|
|
10
|
+
local match = require(script.Parent.match)
|
|
11
|
+
|
|
12
|
+
local NEXT_HOLD_INDEX = 1
|
|
13
|
+
|
|
14
|
+
local function deadzone<T>(input: types.Input<T>, value: number): number
|
|
15
|
+
if value < (input.deadzone or 0.3) then
|
|
16
|
+
return 0
|
|
17
|
+
end
|
|
18
|
+
return value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
--[=[
|
|
22
|
+
@within Input
|
|
23
|
+
@method getGamepad
|
|
24
|
+
@param inputType
|
|
25
|
+
@return number
|
|
26
|
+
Returns the gamepad index of the given inputType, 1 if not a gamepad
|
|
27
|
+
]=]
|
|
28
|
+
local function getGamepad(inputType: Enum.UserInputType)
|
|
29
|
+
-- subtract from the Gamepad1 value to get the input
|
|
30
|
+
if inputType.Value < Enum.UserInputType.Gamepad1.Value or inputType.Value > Enum.UserInputType.Gamepad8.Value then return 1 end
|
|
31
|
+
return inputType.Value - Enum.UserInputType.Gamepad1.Value + 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
local function _reset<T>(input: types.Input<T>, controller: number, inputType: any)
|
|
35
|
+
input.resets[inputType] = {controller, false}-- maybe divide by controller too?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
--[=[
|
|
39
|
+
@within Input
|
|
40
|
+
@method read
|
|
41
|
+
@param controller number?
|
|
42
|
+
@return T, T
|
|
43
|
+
Reads current and previous values for the axis
|
|
44
|
+
```lua
|
|
45
|
+
local current, previous = attack:read()
|
|
46
|
+
```
|
|
47
|
+
]=]
|
|
48
|
+
local function read<T>(input: types.Input<T>, controller: number?): (T, T)
|
|
49
|
+
local default = if input.vector then vector.zero else 0
|
|
50
|
+
return (input.current[controller or 1] or default) :: T, (input.previous[controller or 1] or default) :: T
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
--[=[
|
|
54
|
+
@within Input
|
|
55
|
+
@method pressing
|
|
56
|
+
@param controller number?
|
|
57
|
+
@return boolean
|
|
58
|
+
Gets whether the axis has any active input
|
|
59
|
+
]=]
|
|
60
|
+
local function pressing<T>(input: types.Input<T>, controller: number?): boolean
|
|
61
|
+
local value = read(input, controller)
|
|
62
|
+
local magnitude = if input.vector then vector.magnitude(value) else value
|
|
63
|
+
return magnitude ~= 0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
--[=[
|
|
67
|
+
@within Input
|
|
68
|
+
@method changed
|
|
69
|
+
@param controller number?
|
|
70
|
+
@return boolean
|
|
71
|
+
Gets whether an axis has changed since the last update
|
|
72
|
+
]=]
|
|
73
|
+
local function changed<T>(input: types.Input<T>, controller: number?): boolean
|
|
74
|
+
return input.current[controller or 1] ~= input.previous[controller or 1]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
--[=[
|
|
78
|
+
@within Input
|
|
79
|
+
@method pressed
|
|
80
|
+
@param controller number?
|
|
81
|
+
@return boolean
|
|
82
|
+
Gets whether the axis was activated this update
|
|
83
|
+
]=]
|
|
84
|
+
local function pressed<T>(input: types.Input<T>, controller: number?): boolean
|
|
85
|
+
return changed(input, controller) and pressing(input, controller)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
--[=[
|
|
89
|
+
@within Input
|
|
90
|
+
@method released
|
|
91
|
+
@param controller number?
|
|
92
|
+
@return boolean
|
|
93
|
+
Gets whether the axis was deactivated this update
|
|
94
|
+
]=]
|
|
95
|
+
local function released<T>(input: types.Input<T>, controller: number?): boolean
|
|
96
|
+
return changed(input, controller) and not pressing(input, controller)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
--[=[
|
|
100
|
+
@within Input
|
|
101
|
+
@method hold
|
|
102
|
+
@param value T
|
|
103
|
+
@param controller number?
|
|
104
|
+
@return () -> ()
|
|
105
|
+
Adds a temporary manual input to the axis, and provides a function to release it
|
|
106
|
+
```lua
|
|
107
|
+
local release = attack:hold(1) -- adds 1 to the axis
|
|
108
|
+
--release later
|
|
109
|
+
release() -- removes the added value
|
|
110
|
+
```
|
|
111
|
+
]=]
|
|
112
|
+
local function hold<T>(input: types.Input<T>, value: T, controller: number?): () -> ()
|
|
113
|
+
local id = NEXT_HOLD_INDEX
|
|
114
|
+
NEXT_HOLD_INDEX += 1
|
|
115
|
+
input.active[controller or 1][id] = (value or 1) :: T
|
|
116
|
+
return function()
|
|
117
|
+
input.active[controller or 1][id] = nil
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
--[=[
|
|
122
|
+
@within Input
|
|
123
|
+
@method move
|
|
124
|
+
@param value T
|
|
125
|
+
@param controller number?
|
|
126
|
+
Adds an input to the axis for a single frame
|
|
127
|
+
]=]
|
|
128
|
+
local function move<T>(input: types.Input<T>, value: T, controller: number?)
|
|
129
|
+
local id = NEXT_HOLD_INDEX
|
|
130
|
+
NEXT_HOLD_INDEX += 1
|
|
131
|
+
input.active[controller or 1][id] = (value or 1) :: T
|
|
132
|
+
_reset(input, controller or 1, id)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
--[=[
|
|
137
|
+
@within Input
|
|
138
|
+
@method map
|
|
139
|
+
@param keyMap Map<T>
|
|
140
|
+
Maps input types to an input axis
|
|
141
|
+
```lua
|
|
142
|
+
attack:map {
|
|
143
|
+
Enum.KeyCode.Q,
|
|
144
|
+
Enum.KeyCode.ButtonA,
|
|
145
|
+
}
|
|
146
|
+
-- or to clear all input mappings
|
|
147
|
+
attack:map {}
|
|
148
|
+
```
|
|
149
|
+
]=]
|
|
150
|
+
local function map<T>(input: types.Input<T>, keyMap: types.Map<T>)
|
|
151
|
+
--disconnect previous connections
|
|
152
|
+
for _, connection in input.connections do
|
|
153
|
+
connection:Disconnect()
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
--for detecting the type of value for this input axis for this keymap
|
|
157
|
+
input.vector = nil -- nil, to be detected
|
|
158
|
+
local previousType = nil
|
|
159
|
+
local function setVector(vectorType: boolean, inputType: any)
|
|
160
|
+
if input.vector ~= nil and input.vector ~= vectorType then
|
|
161
|
+
local pre = `{previousType} was {if input.vector then "" else "not "}a vector input`
|
|
162
|
+
local now = `{inputType} is {if vectorType then "" else "not "}a vector input`
|
|
163
|
+
error(`[Axis] Input axis cannot be both vector and scalar.\n\t({pre} and {now})`)
|
|
164
|
+
end
|
|
165
|
+
input.vector = vectorType
|
|
166
|
+
previousType = inputType
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if next(keyMap) == nil then
|
|
170
|
+
return -- let the player clear the keymap with an empty table
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
--set up connections
|
|
174
|
+
local group = {}
|
|
175
|
+
local newMap = {}
|
|
176
|
+
input.keyMap = keyMap
|
|
177
|
+
input.inputMap = newMap
|
|
178
|
+
for index, value in keyMap :: any do
|
|
179
|
+
local inputType = if type(index) == "number" then value else index
|
|
180
|
+
local modifier = if type(index) == "number" then 1 else value
|
|
181
|
+
-- print(`received {index} -> {value}, newmap[{inputType}] = {modifier}`)
|
|
182
|
+
newMap[inputType] = modifier
|
|
183
|
+
local autoType = type(modifier) ~= "number"
|
|
184
|
+
|
|
185
|
+
if inputType == Enum.UserInputType.MouseMovement then
|
|
186
|
+
setVector(true, inputType)
|
|
187
|
+
table.insert(input.connections, UserInputService.InputChanged:Connect(function(inputObject)
|
|
188
|
+
if inputObject.UserInputType ~= Enum.UserInputType.MouseMovement then
|
|
189
|
+
return
|
|
190
|
+
end
|
|
191
|
+
input.active[1][Enum.UserInputType.MouseMovement] = vector.create(inputObject.Delta.X, -inputObject.Delta.Y) * modifier
|
|
192
|
+
_reset(input, 1, Enum.UserInputType.MouseMovement)
|
|
193
|
+
end))
|
|
194
|
+
elseif inputType == Enum.UserInputType.MouseWheel then
|
|
195
|
+
setVector(autoType, inputType)
|
|
196
|
+
table.insert(input.connections, UserInputService.InputChanged:Connect(function(object, processed)
|
|
197
|
+
if processed then
|
|
198
|
+
return
|
|
199
|
+
end
|
|
200
|
+
if object.UserInputType ~= Enum.UserInputType.MouseWheel then
|
|
201
|
+
return
|
|
202
|
+
end
|
|
203
|
+
local position = object.Position.Z
|
|
204
|
+
input.active[1][Enum.UserInputType.MouseWheel] = position * modifier
|
|
205
|
+
_reset(input, 1, Enum.UserInputType.MouseWheel)
|
|
206
|
+
end))
|
|
207
|
+
elseif inputType == Enum.KeyCode.Thumbstick1 then
|
|
208
|
+
setVector(true, inputType)
|
|
209
|
+
table.insert(input.connections, UserInputService.InputChanged:Connect(function(object)
|
|
210
|
+
if object.KeyCode ~= Enum.KeyCode.Thumbstick1 then
|
|
211
|
+
return
|
|
212
|
+
end
|
|
213
|
+
local position = object.Position
|
|
214
|
+
input.active[getGamepad(object.UserInputType)][Enum.KeyCode.Thumbstick1] =
|
|
215
|
+
vector.create(deadzone(input, position.X), deadzone(input, position.Y)) * modifier
|
|
216
|
+
end))
|
|
217
|
+
elseif inputType == Enum.KeyCode.Thumbstick2 then
|
|
218
|
+
setVector(true, inputType)
|
|
219
|
+
table.insert(input.connections, UserInputService.InputChanged:Connect(function(object)
|
|
220
|
+
if object.KeyCode ~= Enum.KeyCode.Thumbstick2 then
|
|
221
|
+
return
|
|
222
|
+
end
|
|
223
|
+
local position = object.Position
|
|
224
|
+
input.active[getGamepad(object.UserInputType)][Enum.KeyCode.Thumbstick1] =
|
|
225
|
+
vector.create(deadzone(input, position.X), deadzone(input, position.Y)) * modifier
|
|
226
|
+
end))
|
|
227
|
+
elseif inputType == UserInputService.TouchSwipe then
|
|
228
|
+
setVector(true, inputType)
|
|
229
|
+
table.insert(input.connections, UserInputService.TouchSwipe:Connect(function(direction: Enum.SwipeDirection)
|
|
230
|
+
input.active[1][UserInputService.TouchSwipe] = modifier * match(direction) {
|
|
231
|
+
Enum.SwipeDirection.Left, vector.create(-1, 0),
|
|
232
|
+
Enum.SwipeDirection.Right, vector.create(1, 0),
|
|
233
|
+
Enum.SwipeDirection.Up, vector.create(0, 1),
|
|
234
|
+
Enum.SwipeDirection.Down, vector.create(0, -1),
|
|
235
|
+
}
|
|
236
|
+
end))
|
|
237
|
+
elseif inputType == UserInputService.TouchPinch then
|
|
238
|
+
setVector(autoType, inputType)
|
|
239
|
+
table.insert(input.connections, UserInputService.TouchPinch:Connect(function(_, scale: number, _, state, sunk)
|
|
240
|
+
if state == Enum.UserInputState.End then
|
|
241
|
+
input.active[1][UserInputService.TouchPinch] = nil
|
|
242
|
+
return
|
|
243
|
+
end
|
|
244
|
+
input.active[1][UserInputService.TouchPinch] = scale :: number & T
|
|
245
|
+
end))
|
|
246
|
+
else
|
|
247
|
+
setVector(autoType, inputType)
|
|
248
|
+
table.insert(group, inputType)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
local function inputHappened(inputObject)
|
|
253
|
+
local controller = getGamepad(inputObject.UserInputType)
|
|
254
|
+
input.active[controller] = input.active[controller] or {}
|
|
255
|
+
local active = input.active[controller]
|
|
256
|
+
for _, enum in group do
|
|
257
|
+
if inputObject.KeyCode ~= enum and inputObject.UserInputType ~= enum then
|
|
258
|
+
continue
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
active[enum] = (if inputObject.UserInputState == Enum.UserInputState.Begin or
|
|
262
|
+
inputObject.UserInputState == Enum.UserInputState.Change then input.inputMap[enum] else nil) :: (nil & T)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
local inputBegan = function(inputObject, sunk)
|
|
267
|
+
if not sunk then
|
|
268
|
+
inputHappened(inputObject)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
table.insert(input.connections, UserInputService.InputBegan:Connect(inputBegan))
|
|
272
|
+
table.insert(input.connections, UserInputService.InputEnded:Connect(inputHappened))
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
--[=[
|
|
276
|
+
@within Input
|
|
277
|
+
@method update
|
|
278
|
+
Updates the current and previous values of the input axis
|
|
279
|
+
]=]
|
|
280
|
+
local function update<T>(input: types.Input<T>)
|
|
281
|
+
-- reset old values
|
|
282
|
+
for inputType, reset in input.resets do
|
|
283
|
+
if not reset[2] then
|
|
284
|
+
reset[2] = true
|
|
285
|
+
continue
|
|
286
|
+
end
|
|
287
|
+
input.active[reset[1]][inputType] = nil
|
|
288
|
+
input.resets[inputType] = nil
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
-- iterate through all controllers
|
|
292
|
+
for i, set in input.active do
|
|
293
|
+
-- set last frame
|
|
294
|
+
input.previous[i] = input.current[i]
|
|
295
|
+
|
|
296
|
+
local result: T? = nil -- sum current values
|
|
297
|
+
for key, value: T in set do
|
|
298
|
+
if not result then
|
|
299
|
+
result = value
|
|
300
|
+
continue
|
|
301
|
+
end
|
|
302
|
+
result += value
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
input.current[i] = result :: T
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
local function new<T>(inputMap: types.Map<T> & { deadzone: number? }): types.Input<T>
|
|
310
|
+
local input: types.Input<T> = {
|
|
311
|
+
vector = false,
|
|
312
|
+
current = {},
|
|
313
|
+
previous = {},
|
|
314
|
+
active = {
|
|
315
|
+
{}, -- separate input axes for each controller
|
|
316
|
+
},
|
|
317
|
+
resets = {}, --resets input on next update
|
|
318
|
+
connections = {},
|
|
319
|
+
inputMap = inputMap,
|
|
320
|
+
deadzone = inputMap.deadzone,
|
|
321
|
+
|
|
322
|
+
read = read,
|
|
323
|
+
pressing = pressing,
|
|
324
|
+
pressed = pressed,
|
|
325
|
+
released = released,
|
|
326
|
+
changed = changed,
|
|
327
|
+
hold = hold,
|
|
328
|
+
map = map,
|
|
329
|
+
update = update,
|
|
330
|
+
move = move,
|
|
331
|
+
}
|
|
332
|
+
map(input, inputMap)
|
|
333
|
+
|
|
334
|
+
return input
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
return new :: types.InputConstructor
|
package/out/match.luau
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
--[[match statement that allows for custom equals metatable function
|
|
2
|
+
```lua
|
|
3
|
+
local result = match "hello" {
|
|
4
|
+
"world", function()
|
|
5
|
+
return "failed"
|
|
6
|
+
end,
|
|
7
|
+
"hello", function()
|
|
8
|
+
return "success!"
|
|
9
|
+
end,
|
|
10
|
+
}
|
|
11
|
+
```]]
|
|
12
|
+
return function<T, V...>(value: T, ...: V...)
|
|
13
|
+
local args = {...}
|
|
14
|
+
return function<R>(cases: {R | (T, V...) -> R}): R?
|
|
15
|
+
assert(type(cases) == 'table', "cases needs to be table")
|
|
16
|
+
for i = 1, #cases, 2 do
|
|
17
|
+
if value == cases[i] then
|
|
18
|
+
local result = cases[i + 1]
|
|
19
|
+
return if type(result) == "function" then
|
|
20
|
+
result(value,unpack(args)) else result
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
return nil
|
|
24
|
+
end
|
|
25
|
+
end
|
package/out/types.luau
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
@within Axis
|
|
4
|
+
@type DeviceType "Desktop" | "Touch" | "Controller"
|
|
5
|
+
]=]
|
|
6
|
+
export type DeviceType = "Desktop" | "Touch" | "Controller"
|
|
7
|
+
|
|
8
|
+
--[=[
|
|
9
|
+
@within Axis
|
|
10
|
+
@type Map<T> { [Enum | string]: T } & { Enum.KeyCode | Enum.UserInputType }
|
|
11
|
+
]=]
|
|
12
|
+
export type Map<T> = { [any]: any }
|
|
13
|
+
--{ [Enum.UserInputType | Enum.KeyCode | string]: T } & { Enum.KeyCode | Enum.UserInputType }
|
|
14
|
+
|
|
15
|
+
export type Input<T> = {
|
|
16
|
+
read: (Input<T>, controller: number?) -> (T, T),
|
|
17
|
+
pressing: (Input<T>, controller: number?) -> boolean,
|
|
18
|
+
pressed: (Input<T>, controller: number?) -> boolean,
|
|
19
|
+
released: (Input<T>, controller: number?) -> boolean,
|
|
20
|
+
changed: (Input<T>, controller: number?) -> boolean,
|
|
21
|
+
hold: (Input<T>, value: T, controller: number?) -> (),
|
|
22
|
+
move: (Input<T>, value: T, controller: number?) -> (),
|
|
23
|
+
map: (Input<T>, keyMap: Map<T>) -> nil,
|
|
24
|
+
update: (Input<T>) -> nil,
|
|
25
|
+
|
|
26
|
+
deadzone: number?,
|
|
27
|
+
vector: boolean,
|
|
28
|
+
current: { T },
|
|
29
|
+
previous: { T },
|
|
30
|
+
active: { { [any]: T } },
|
|
31
|
+
resets: { [any]: { any } },
|
|
32
|
+
connections: { RBXScriptConnection },
|
|
33
|
+
keyMap: Map<T>,
|
|
34
|
+
inputMap: { [Enum.KeyCode | Enum.UserInputType]: T },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type InputConstructor = <T>(Map<T> | (Map<T> & { deadzone: number? })) -> Input<T>
|
|
38
|
+
|
|
39
|
+
export type Axis = {
|
|
40
|
+
device: (Enum.UserInputType?) -> DeviceType,
|
|
41
|
+
update: (inputs: { [any]: Input<any> } ) -> nil,
|
|
42
|
+
clear: (any) -> nil,
|
|
43
|
+
input: InputConstructor,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rbxts/axis",
|
|
3
|
+
"version": "0.2.3-v.1",
|
|
4
|
+
"description": "roblox-ts typings for NeonD00m/axis",
|
|
5
|
+
"main": "out/init.lua",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rbxtsc",
|
|
8
|
+
"watch": "rbxtsc -w",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/teakzc/axis-types.git"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://neond00m.github.io/Axis/",
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "teakzc",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"type": "commonjs",
|
|
20
|
+
"types": "out/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"out",
|
|
23
|
+
"!**/*.tsbuildinfo"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
30
|
+
"@rbxts/types": "^1.0.906",
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^8.55.0",
|
|
32
|
+
"@typescript-eslint/parser": "^8.55.0",
|
|
33
|
+
"eslint": "^9.39.2",
|
|
34
|
+
"eslint-config-prettier": "^10.1.8",
|
|
35
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
36
|
+
"eslint-plugin-roblox-ts": "^1.3.1",
|
|
37
|
+
"prettier": "^3.8.1",
|
|
38
|
+
"roblox-ts": "^3.0.0",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
}
|
|
41
|
+
}
|