@benev/tact 0.1.0-1 → 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 +176 -115
- package/package.json +3 -2
- package/s/{station → core/bindings}/types.ts +4 -20
- package/s/core/controllers/controller.ts +7 -0
- package/s/core/controllers/infra/group.ts +17 -0
- package/s/{station/devices → core/controllers}/infra/sampler.ts +3 -3
- package/s/{station/devices → core/controllers/standard}/gamepad.ts +6 -6
- package/s/core/controllers/standard/index.ts +7 -0
- package/s/{station/devices → core/controllers/standard}/keyboard.ts +3 -3
- package/s/{station/devices → core/controllers/standard}/pointer.ts +34 -34
- package/s/{nubs/stick/device.ts → core/controllers/standard/stick.ts} +3 -3
- package/s/{nubs/virtual-gamepad/device.ts → core/controllers/standard/virtual-gamepad.ts} +5 -5
- package/s/core/controllers/types.ts +4 -0
- package/s/core/core.test.ts +90 -0
- package/s/core/hub/auto-gamepads.ts +8 -0
- package/s/{station/parts/switchboard-bindings.ts → core/hub/bindings.ts} +4 -4
- package/s/core/hub/hub.ts +102 -0
- package/s/core/index.ts +19 -0
- package/s/{station/parts → core/port}/action.ts +3 -9
- package/s/core/port/port.ts +34 -0
- package/s/core/port/resolution/defaults.ts +30 -0
- package/s/{station/parts/routines/lensing_algorithm.ts → core/port/resolution/lens-algo.ts} +13 -11
- package/s/core/port/resolution/resolver.ts +77 -0
- package/s/core/port/resolution/types.ts +9 -0
- package/s/core/port/types.ts +10 -0
- package/s/core/port/utils/aggregate_samples_into_map.ts +20 -0
- package/s/core/port/utils/wipe_samples_map.ts +8 -0
- package/s/core/testing/testing.ts +50 -0
- package/s/demo/main.bundle.ts +2 -2
- package/s/index.ts +1 -11
- package/s/nubs/stick/view.ts +2 -2
- package/s/nubs/virtual-gamepad/view.ts +6 -6
- package/s/tests.test.ts +2 -4
- package/s/{station/utils/tmin.ts → utils/quick-math.ts} +6 -0
- package/x/{station → core/bindings}/types.d.ts +4 -16
- package/x/core/bindings/types.js +5 -0
- package/x/core/bindings/types.js.map +1 -0
- package/x/core/controllers/controller.d.ts +4 -0
- package/x/core/controllers/controller.js +3 -0
- package/x/core/controllers/controller.js.map +1 -0
- package/x/core/controllers/infra/group.d.ts +7 -0
- package/x/core/controllers/infra/group.js +13 -0
- package/x/core/controllers/infra/group.js.map +1 -0
- package/x/core/controllers/infra/sampler.d.ts +8 -0
- package/x/{station/devices → core/controllers}/infra/sampler.js +2 -2
- package/x/core/controllers/infra/sampler.js.map +1 -0
- package/x/core/controllers/standard/gamepad.d.ts +10 -0
- package/x/{station/devices → core/controllers/standard}/gamepad.js +5 -5
- package/x/core/controllers/standard/gamepad.js.map +1 -0
- package/x/core/controllers/standard/index.d.ts +5 -0
- package/x/core/controllers/standard/index.js +6 -0
- package/x/core/controllers/standard/index.js.map +1 -0
- package/x/{station/devices → core/controllers/standard}/keyboard.d.ts +3 -3
- package/x/{station/devices → core/controllers/standard}/keyboard.js +3 -3
- package/x/core/controllers/standard/keyboard.js.map +1 -0
- package/x/{station/devices → core/controllers/standard}/pointer.d.ts +3 -3
- package/x/{station/devices → core/controllers/standard}/pointer.js +29 -29
- package/x/core/controllers/standard/pointer.js.map +1 -0
- package/x/{nubs/stick/device.d.ts → core/controllers/standard/stick.d.ts} +2 -2
- package/x/{nubs/stick/device.js → core/controllers/standard/stick.js} +4 -4
- package/x/core/controllers/standard/stick.js.map +1 -0
- package/x/core/controllers/standard/virtual-gamepad.d.ts +7 -0
- package/x/{nubs/virtual-gamepad/device.js → core/controllers/standard/virtual-gamepad.js} +6 -6
- package/x/core/controllers/standard/virtual-gamepad.js.map +1 -0
- package/x/core/controllers/types.d.ts +2 -0
- package/x/core/controllers/types.js +2 -0
- package/x/core/controllers/types.js.map +1 -0
- package/x/core/controllers/utils/modprefix.js.map +1 -0
- package/x/core/core.test.d.ts +11 -0
- package/x/core/core.test.js +84 -0
- package/x/core/core.test.js.map +1 -0
- package/x/core/hub/auto-gamepads.d.ts +2 -0
- package/x/core/hub/auto-gamepads.js +6 -0
- package/x/core/hub/auto-gamepads.js.map +1 -0
- package/x/core/hub/bindings.d.ts +2 -0
- package/x/{station/parts/switchboard-bindings.js → core/hub/bindings.js} +4 -4
- package/x/core/hub/bindings.js.map +1 -0
- package/x/core/hub/hub.d.ts +29 -0
- package/x/core/hub/hub.js +91 -0
- package/x/core/hub/hub.js.map +1 -0
- package/x/core/index.d.ts +14 -0
- package/x/core/index.js +15 -0
- package/x/core/index.js.map +1 -0
- package/x/{station/parts → core/port}/action.d.ts +1 -3
- package/x/{station/parts → core/port}/action.js +3 -10
- package/x/core/port/action.js.map +1 -0
- package/x/core/port/port.d.ts +12 -0
- package/x/core/port/port.js +25 -0
- package/x/core/port/port.js.map +1 -0
- package/x/core/port/resolution/defaults.d.ts +4 -0
- package/x/{station/parts → core/port/resolution}/defaults.js +4 -3
- package/x/core/port/resolution/defaults.js.map +1 -0
- package/x/core/port/resolution/lens-algo.d.ts +2 -0
- package/x/{station/parts/routines/lensing_algorithm.js → core/port/resolution/lens-algo.js} +9 -8
- package/x/core/port/resolution/lens-algo.js.map +1 -0
- package/x/core/port/resolution/resolver.d.ts +9 -0
- package/x/core/port/resolution/resolver.js +64 -0
- package/x/core/port/resolution/resolver.js.map +1 -0
- package/x/core/port/resolution/types.d.ts +6 -0
- package/x/core/port/resolution/types.js +2 -0
- package/x/core/port/resolution/types.js.map +1 -0
- package/x/core/port/types.d.ts +7 -0
- package/x/core/port/types.js +2 -0
- package/x/core/port/types.js.map +1 -0
- package/x/core/port/utils/aggregate_samples_into_map.d.ts +3 -0
- package/x/core/port/utils/aggregate_samples_into_map.js +11 -0
- package/x/core/port/utils/aggregate_samples_into_map.js.map +1 -0
- package/x/core/port/utils/is-pressed.js.map +1 -0
- package/x/core/port/utils/wipe_samples_map.d.ts +2 -0
- package/x/core/port/utils/wipe_samples_map.js +5 -0
- package/x/core/port/utils/wipe_samples_map.js.map +1 -0
- package/x/{station → core}/testing/testing.d.ts +8 -8
- package/x/core/testing/testing.js +42 -0
- package/x/core/testing/testing.js.map +1 -0
- package/x/demo/main.bundle.js +2 -2
- package/x/demo/main.bundle.js.map +1 -1
- package/x/demo/main.bundle.min.js +1 -1
- package/x/demo/main.bundle.min.js.map +4 -4
- package/x/index.d.ts +1 -11
- package/x/index.html +3 -3
- package/x/index.js +1 -11
- package/x/index.js.map +1 -1
- package/x/nubs/stick/view.d.ts +2 -2
- package/x/nubs/stick/view.js.map +1 -1
- package/x/nubs/virtual-gamepad/view.d.ts +2 -2
- package/x/nubs/virtual-gamepad/view.js +5 -5
- package/x/nubs/virtual-gamepad/view.js.map +1 -1
- package/x/tests.test.js +2 -4
- package/x/tests.test.js.map +1 -1
- package/x/{station/utils/tmax.d.ts → utils/quick-math.d.ts} +1 -0
- package/x/utils/quick-math.js +11 -0
- package/x/utils/quick-math.js.map +1 -0
- package/s/station/devices/infra/device.ts +0 -7
- package/s/station/devices/infra/group.ts +0 -17
- package/s/station/parts/defaults.ts +0 -28
- package/s/station/parts/resolver.ts +0 -73
- package/s/station/parts/routines/aggregate_samples_into_map.ts +0 -20
- package/s/station/parts/routines/build_updatable_actions_structure.ts +0 -29
- package/s/station/station.test.ts +0 -86
- package/s/station/station.ts +0 -47
- package/s/station/switchboard.ts +0 -107
- package/s/station/testing/testing.ts +0 -47
- package/s/station/utils/tmax.ts +0 -7
- package/x/nubs/stick/device.js.map +0 -1
- package/x/nubs/virtual-gamepad/device.d.ts +0 -7
- package/x/nubs/virtual-gamepad/device.js.map +0 -1
- package/x/station/devices/gamepad.d.ts +0 -10
- package/x/station/devices/gamepad.js.map +0 -1
- package/x/station/devices/infra/device.d.ts +0 -4
- package/x/station/devices/infra/device.js +0 -3
- package/x/station/devices/infra/device.js.map +0 -1
- package/x/station/devices/infra/group.d.ts +0 -7
- package/x/station/devices/infra/group.js +0 -13
- package/x/station/devices/infra/group.js.map +0 -1
- package/x/station/devices/infra/sampler.d.ts +0 -8
- package/x/station/devices/infra/sampler.js.map +0 -1
- package/x/station/devices/keyboard.js.map +0 -1
- package/x/station/devices/pointer.js.map +0 -1
- package/x/station/parts/action.js.map +0 -1
- package/x/station/parts/defaults.d.ts +0 -5
- package/x/station/parts/defaults.js.map +0 -1
- package/x/station/parts/resolver.d.ts +0 -10
- package/x/station/parts/resolver.js +0 -63
- package/x/station/parts/resolver.js.map +0 -1
- package/x/station/parts/routines/aggregate_samples_into_map.d.ts +0 -3
- package/x/station/parts/routines/aggregate_samples_into_map.js +0 -11
- package/x/station/parts/routines/aggregate_samples_into_map.js.map +0 -1
- package/x/station/parts/routines/build_updatable_actions_structure.d.ts +0 -5
- package/x/station/parts/routines/build_updatable_actions_structure.js +0 -18
- package/x/station/parts/routines/build_updatable_actions_structure.js.map +0 -1
- package/x/station/parts/routines/lensing_algorithm.d.ts +0 -2
- package/x/station/parts/routines/lensing_algorithm.js.map +0 -1
- package/x/station/parts/switchboard-bindings.d.ts +0 -2
- package/x/station/parts/switchboard-bindings.js.map +0 -1
- package/x/station/station.d.ts +0 -15
- package/x/station/station.js +0 -35
- package/x/station/station.js.map +0 -1
- package/x/station/station.test.d.ts +0 -11
- package/x/station/station.test.js +0 -80
- package/x/station/station.test.js.map +0 -1
- package/x/station/switchboard.d.ts +0 -30
- package/x/station/switchboard.js +0 -90
- package/x/station/switchboard.js.map +0 -1
- package/x/station/testing/testing.js +0 -39
- package/x/station/testing/testing.js.map +0 -1
- package/x/station/types.js +0 -5
- package/x/station/types.js.map +0 -1
- package/x/station/utils/is-pressed.js.map +0 -1
- package/x/station/utils/modprefix.js.map +0 -1
- package/x/station/utils/tmax.js +0 -6
- package/x/station/utils/tmax.js.map +0 -1
- package/x/station/utils/tmin.d.ts +0 -1
- package/x/station/utils/tmin.js +0 -6
- package/x/station/utils/tmin.js.map +0 -1
- /package/s/{station → core/controllers}/utils/modprefix.ts +0 -0
- /package/s/{station → core/port}/utils/is-pressed.ts +0 -0
- /package/x/{station → core/controllers}/utils/modprefix.d.ts +0 -0
- /package/x/{station → core/controllers}/utils/modprefix.js +0 -0
- /package/x/{station → core/port}/utils/is-pressed.d.ts +0 -0
- /package/x/{station → core/port}/utils/is-pressed.js +0 -0
package/README.md
CHANGED
|
@@ -1,50 +1,128 @@
|
|
|
1
1
|
|
|
2
2
|
# @benev/tact
|
|
3
|
-
>
|
|
3
|
+
> web game input library, from keypress to couch co-op
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
npm install @benev/tact
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- 🔌 **
|
|
13
|
-
-
|
|
9
|
+
- 🛹 **deck** user input coordinator with bindings persistence
|
|
10
|
+
- 🎮 **controllers** produce user input samples
|
|
11
|
+
- 🧩 **bindings** describe how actions interpret samples
|
|
12
|
+
- 🔌 **port** updates actions by interpreting samples
|
|
13
|
+
- 🛞 **hub** plugs controllers into ports (multi-gamepad couch co-op!)
|
|
14
|
+
- 📱 **nubs** is mobile ui virtual gamepad stuff
|
|
15
|
+
|
|
16
|
+
|
|
14
17
|
|
|
15
18
|
<br/><br/>
|
|
16
19
|
|
|
17
|
-
## 🍋 tact
|
|
18
|
-
>
|
|
20
|
+
## 🍋 tact deck
|
|
21
|
+
> *user input coordinator with bindings persistence*
|
|
22
|
+
|
|
23
|
+
the deck is the heart of tact.. it ties all the important parts together..
|
|
24
|
+
|
|
25
|
+
### 🛹 deck setup
|
|
26
|
+
- **import stuff from tact**
|
|
27
|
+
```ts
|
|
28
|
+
import * as tact from "@benev/tact"
|
|
29
|
+
```
|
|
30
|
+
- **setup your deck**
|
|
31
|
+
```ts
|
|
32
|
+
const deck = new tact.Deck({
|
|
33
|
+
ports: 4,
|
|
34
|
+
kv: tact.Deck.localStorageKv(),
|
|
35
|
+
defaultBindings: tact.Hub.bindings({
|
|
36
|
+
walking: {
|
|
37
|
+
forward: [
|
|
38
|
+
{lenses: [{code: "KeyW"}]},
|
|
39
|
+
{lenses: [{code: "gamepad.stick.left.up"}]},
|
|
40
|
+
],
|
|
41
|
+
jump: [
|
|
42
|
+
{lenses: [{code: "Space"}]},
|
|
43
|
+
{lenses: [{code: "gamepad.a"}]},
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
gunning: {
|
|
47
|
+
shoot: [
|
|
48
|
+
{lenses: [{code: "pointer.button.left"}]},
|
|
49
|
+
{lenses: [{code: "gamepad.trigger.right"}]},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 🛹 plug controllers into the hub
|
|
57
|
+
- **plug a keyboard/mouse player into the hub**
|
|
58
|
+
```ts
|
|
59
|
+
deck.hub.plug(
|
|
60
|
+
new tact.GroupController(
|
|
61
|
+
new tact.KeyboardController(),
|
|
62
|
+
new tact.PointerController(),
|
|
63
|
+
new tact.VirtualGamepadController(),
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
- **auto connect/disconnect gamepads as they come and go**
|
|
68
|
+
```ts
|
|
69
|
+
tact.autoGamepads(deck.hub.plug)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 🛹 do your gameplay
|
|
73
|
+
- **start with what modes you want enabled in your game**
|
|
74
|
+
```ts
|
|
75
|
+
for (const port of deck.ports)
|
|
76
|
+
port.modes.adds("walking", "gunning")
|
|
77
|
+
```
|
|
78
|
+
- **poll the deck, interrogate actions for your gameplay**
|
|
79
|
+
```ts
|
|
80
|
+
onEachTickInYourGame(() => {
|
|
81
|
+
|
|
82
|
+
// do your polling
|
|
83
|
+
const [p1, p2, p3, p4] = deck.hub.poll()
|
|
84
|
+
|
|
85
|
+
// check if the first player is pressing "forward" action
|
|
86
|
+
p1.actions.walking.forward.pressed // true
|
|
87
|
+
|
|
88
|
+
// check how hard the second player is pulling that trigger
|
|
89
|
+
p2.actions.gunning.shoot.value // 0.123
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
<br/><br/>
|
|
19
96
|
|
|
20
|
-
|
|
97
|
+
## 🍋 tact controllers
|
|
98
|
+
> *produces user input "samples"*
|
|
99
|
+
|
|
100
|
+
### 🎮 polling is good, actually
|
|
21
101
|
- tact operates on the basis of *polling*
|
|
22
102
|
- *"but polling is bad"* says you — but no — you're wrong — polling is unironically *based,* and you *should* do it
|
|
23
103
|
- in a game, we want to be processing our inputs *every frame*
|
|
24
104
|
- the gift of polling is total control over *when* inputs are processed
|
|
25
105
|
- i will elaborate no further 🗿
|
|
26
106
|
|
|
27
|
-
###
|
|
28
|
-
- make a
|
|
107
|
+
### 🎮 basically how a controller works
|
|
108
|
+
- make a controller
|
|
29
109
|
```ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const device = new KeyboardDevice(window)
|
|
110
|
+
const keyboard = new tact.KeyboardController()
|
|
33
111
|
```
|
|
34
112
|
- take samples each frame
|
|
35
113
|
```ts
|
|
36
|
-
const samples =
|
|
114
|
+
const samples = keyboard.takeSamples()
|
|
37
115
|
// [
|
|
38
116
|
// ["KeyA", 1],
|
|
39
117
|
// ["Space", 0]
|
|
40
118
|
// ]
|
|
41
119
|
```
|
|
42
|
-
- dispose
|
|
120
|
+
- dispose when you're done with it
|
|
43
121
|
```ts
|
|
44
|
-
|
|
122
|
+
keyboard.dispose()
|
|
45
123
|
```
|
|
46
124
|
|
|
47
|
-
###
|
|
125
|
+
### 🎮 samples explained
|
|
48
126
|
- a sample is a raw input of type `[code: string, value: number]`
|
|
49
127
|
- a sample has a `code` string
|
|
50
128
|
- it's either a [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values), like `KeyA`
|
|
@@ -57,7 +135,7 @@ npm install @benev/tact
|
|
|
57
135
|
- sometimes we use numbers greater then `1`, like for dots of pointer movement like in `pointer.move.up`
|
|
58
136
|
- don't worry about sensitivity, deadzones, values like `0.00001` — actions will account for all that using bindings later on
|
|
59
137
|
|
|
60
|
-
###
|
|
138
|
+
### 🎮 sample code modprefixes
|
|
61
139
|
- here at tact, we have this nifty `modprefix` convention
|
|
62
140
|
- consider a keycode like `KeyA`
|
|
63
141
|
- `ctrl-KeyA` means the "ctrl" modifier was held
|
|
@@ -68,8 +146,8 @@ npm install @benev/tact
|
|
|
68
146
|
- `x-KeyA` means *no* modifier was held (exclusive)
|
|
69
147
|
- `KeyA` doesn't care if any modifiers were held or not
|
|
70
148
|
|
|
71
|
-
###
|
|
72
|
-
- **
|
|
149
|
+
### 🎮 sample code reference
|
|
150
|
+
- **KeyboardController**
|
|
73
151
|
- any [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values)
|
|
74
152
|
- `KeyA`
|
|
75
153
|
- `Space`
|
|
@@ -80,7 +158,7 @@ npm install @benev/tact
|
|
|
80
158
|
- `alt-shift-Space`
|
|
81
159
|
- `x-Digit2`
|
|
82
160
|
- etc
|
|
83
|
-
- **
|
|
161
|
+
- **PointerController**
|
|
84
162
|
- mouse buttons (plus modprefixes)
|
|
85
163
|
- `pointer.button.left`
|
|
86
164
|
- `pointer.button.right`
|
|
@@ -97,7 +175,7 @@ npm install @benev/tact
|
|
|
97
175
|
- `pointer.move.down`
|
|
98
176
|
- `pointer.move.left`
|
|
99
177
|
- `pointer.move.right`
|
|
100
|
-
- **
|
|
178
|
+
- **GamepadController**
|
|
101
179
|
- gamepad buttons
|
|
102
180
|
- `gamepad.a`
|
|
103
181
|
- `gamepad.b`
|
|
@@ -126,17 +204,17 @@ npm install @benev/tact
|
|
|
126
204
|
- `gamepad.stick.right.left`
|
|
127
205
|
- `gamepad.stick.right.right`
|
|
128
206
|
|
|
207
|
+
|
|
208
|
+
|
|
129
209
|
<br/><br/>
|
|
130
210
|
|
|
131
211
|
## 🍋 tact bindings
|
|
132
|
-
> keybindings! they describe how actions interpret samples
|
|
212
|
+
> *keybindings! they describe how actions interpret samples*
|
|
133
213
|
|
|
134
|
-
###
|
|
214
|
+
### 🧩 bindings example
|
|
135
215
|
- let's start with a small example:
|
|
136
216
|
```ts
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const bindings = asBindings({
|
|
217
|
+
const bindings = tact.asBindings({
|
|
140
218
|
walking: {
|
|
141
219
|
forward: [{lenses: [{code: "KeyW"}]}],
|
|
142
220
|
jump: [{lenses: [{code: "Space"}]}],
|
|
@@ -152,32 +230,46 @@ npm install @benev/tact
|
|
|
152
230
|
- 🚨 TODO okay these rules are complex and i'm gonna rework them soon
|
|
153
231
|
- whole modes can be enabled or disabled
|
|
154
232
|
|
|
233
|
+
|
|
234
|
+
|
|
155
235
|
<br/><br/>
|
|
156
236
|
|
|
157
|
-
## 🍋 tact
|
|
158
|
-
> polling gives you actions
|
|
237
|
+
## 🍋 tact port
|
|
238
|
+
> *polling gives you "actions"*
|
|
159
239
|
|
|
160
|
-
###
|
|
161
|
-
-
|
|
240
|
+
### 🔌 port basics
|
|
241
|
+
- **make a port**
|
|
162
242
|
```ts
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
243
|
+
const port = new tact.Port(bindings)
|
|
244
|
+
```
|
|
245
|
+
- **attach some controllers to the port**
|
|
246
|
+
```ts
|
|
247
|
+
port.controllers
|
|
248
|
+
.add(new tact.KeyboardController())
|
|
249
|
+
.add(new tact.PointerController())
|
|
250
|
+
.add(new tact.VirtualGamepadController())
|
|
251
|
+
```
|
|
252
|
+
- you can add/delete controllers from the set any time
|
|
253
|
+
- **don't forget to enable modes!**
|
|
254
|
+
```ts
|
|
255
|
+
port.modes.add("walking")
|
|
256
|
+
```
|
|
257
|
+
- if you don't enable any modes, no actions will happen
|
|
258
|
+
- actions only happen for enabled modes
|
|
259
|
+
- you can toggle modes on and off by adding/deleting them from the modes set
|
|
260
|
+
- **you can update the bindings any time**
|
|
261
|
+
```ts
|
|
262
|
+
port.bindings = freshBindings
|
|
171
263
|
```
|
|
172
264
|
|
|
173
|
-
###
|
|
174
|
-
- poll the
|
|
265
|
+
### 🔌 interrogating actions
|
|
266
|
+
- **poll the port every frame**
|
|
175
267
|
```ts
|
|
176
|
-
|
|
268
|
+
const actions = port.poll()
|
|
177
269
|
```
|
|
178
|
-
- now you
|
|
270
|
+
- **now you can inspect the `actions`**
|
|
179
271
|
```ts
|
|
180
|
-
|
|
272
|
+
actions.walking.forward.value // 1
|
|
181
273
|
```
|
|
182
274
|
- `walking` is a `mode`
|
|
183
275
|
- `forward` is an `action`
|
|
@@ -187,113 +279,82 @@ npm install @benev/tact
|
|
|
187
279
|
- `action.pressed` — true if the value > 0
|
|
188
280
|
- `action.down` — true for one frame when the key goes from up to down
|
|
189
281
|
- `action.up` — true for one frame when the key goes from down to up
|
|
190
|
-
- `action.on(action => {})` — react to changes ([`@e280/stz`](https://github.com/e280/stz) sub fn)
|
|
191
|
-
- `action.onDown(action => {})` — react only on down ([`@e280/stz`](https://github.com/e280/stz) sub fn)
|
|
192
282
|
|
|
193
|
-
### 🥝 more about station
|
|
194
|
-
- you can enable/disable modes like this (it's a set)
|
|
195
|
-
```ts
|
|
196
|
-
station.modes.add("gunning")
|
|
197
|
-
// now the "gunning" actions can fire
|
|
198
283
|
|
|
199
|
-
station.modes.delete("walking")
|
|
200
|
-
// now the "walking" actions *cannot* fire
|
|
201
|
-
```
|
|
202
|
-
- you can add/remove devices from the set any time
|
|
203
|
-
```ts
|
|
204
|
-
station.devices.add(new GamepadDevice(pad))
|
|
205
|
-
```
|
|
206
|
-
- you can update the bindings at runtime
|
|
207
|
-
```ts
|
|
208
|
-
station.bindings = bindings2
|
|
209
|
-
```
|
|
210
284
|
|
|
211
285
|
<br/><br/>
|
|
212
286
|
|
|
213
|
-
## 🍋 tact
|
|
214
|
-
> multiple gamepads! couch co-op is so back
|
|
287
|
+
## 🍋 tact hub
|
|
288
|
+
> *multiple gamepads! couch co-op is so back*
|
|
215
289
|
|
|
216
|
-
|
|
217
|
-
- you know the way old timey game consoles had controller ports? and then players could plug their controller into whatever port they wanted? and then you could unplug and replug your controller into a different port? yeah — that's what switchboard does.
|
|
218
|
-
- with the switchboard, think of the "stations" as controller ports, and the "devices" as player controllers.
|
|
219
|
-
- import stuff:
|
|
220
|
-
```ts
|
|
221
|
-
import {
|
|
222
|
-
Switchboard, Station,
|
|
223
|
-
GroupDevice, GamepadDevice, KeyboardDevice, PointerDevice,
|
|
224
|
-
} from "@benev/tact"
|
|
225
|
-
```
|
|
290
|
+
you know the way old-timey game consoles had four controller ports on the front?
|
|
226
291
|
|
|
227
|
-
|
|
228
|
-
|
|
292
|
+
the hub embraces that analogy, helping you coordinate the plugging and unplugging of virtual controllers into its virtual ports.
|
|
293
|
+
|
|
294
|
+
### 🛞 create a hub with ports
|
|
295
|
+
- **adopt standard hub bindings**
|
|
229
296
|
```ts
|
|
230
|
-
// transform your game's bindings into
|
|
231
|
-
const
|
|
297
|
+
// transform your game's bindings into hub-friendly bindings
|
|
298
|
+
const hubBindings = tact.Hub.bindings(bindings)
|
|
232
299
|
```
|
|
233
|
-
- this
|
|
234
|
-
-
|
|
300
|
+
- this augments your bindings with standard hub-specific bindings
|
|
301
|
+
- this lets players to shimmy what port their controller is plugged into
|
|
302
|
+
- gamepad: hold gamma (middle button) and press bumpers
|
|
235
303
|
- keyboard: left bracket or right bracket
|
|
236
|
-
- **make
|
|
304
|
+
- **make hub with multiple ports at the ready**
|
|
237
305
|
```ts
|
|
238
|
-
const
|
|
239
|
-
new
|
|
240
|
-
new
|
|
241
|
-
new
|
|
242
|
-
new
|
|
306
|
+
const hub = new tact.Hub([
|
|
307
|
+
new tact.Port(hubBindings),
|
|
308
|
+
new tact.Port(hubBindings),
|
|
309
|
+
new tact.Port(hubBindings),
|
|
310
|
+
new tact.Port(hubBindings),
|
|
243
311
|
])
|
|
244
312
|
```
|
|
245
|
-
- yes that's right — each player
|
|
313
|
+
- yes that's right — each player port gets its own bindings 🤯
|
|
246
314
|
|
|
247
|
-
###
|
|
248
|
-
- **let's
|
|
315
|
+
### 🛞 plug in some controllers
|
|
316
|
+
- **let's plug in the keyboard/mouse player**
|
|
249
317
|
```ts
|
|
250
|
-
|
|
251
|
-
new
|
|
252
|
-
new
|
|
253
|
-
new
|
|
318
|
+
hub.plug(
|
|
319
|
+
new tact.GroupController(
|
|
320
|
+
new tact.KeyboardController(),
|
|
321
|
+
new tact.PointerController(),
|
|
322
|
+
new tact.VirtualGamepadController(),
|
|
254
323
|
)
|
|
255
324
|
)
|
|
256
325
|
```
|
|
257
|
-
- the
|
|
326
|
+
- the hub requires a single controller to represent a player, thus we can use a `GroupController` to combine multple controllers into one
|
|
258
327
|
- **wire up gamepad auto connect/disconnect**
|
|
259
328
|
```ts
|
|
260
|
-
|
|
329
|
+
tact.autoGamepads(hub.plug)
|
|
261
330
|
```
|
|
262
331
|
|
|
263
|
-
###
|
|
332
|
+
### 🛞 it's gaming time
|
|
264
333
|
- **do your polling, interrogate those actions**
|
|
265
334
|
```ts
|
|
266
|
-
const [p1, p2, p3, p4] =
|
|
267
|
-
|
|
268
|
-
// poll them all
|
|
269
|
-
switchboard.poll(Date.now())
|
|
335
|
+
const [p1, p2, p3, p4] = hub.poll()
|
|
270
336
|
|
|
271
|
-
p1.
|
|
272
|
-
p2.
|
|
337
|
+
p1.walking.jump.value // 1
|
|
338
|
+
p2.walking.jump.value // 0
|
|
273
339
|
```
|
|
274
340
|
|
|
275
|
-
|
|
276
|
-
- `switchboard.stations` — direct access to the array of stations
|
|
277
|
-
- `switchboard.isActive(p1)` — check if there's a switchboard-connected-device assigned to this station
|
|
278
|
-
- `switchboard.shimmy(device, 1)` — shimmy a device forward one station
|
|
279
|
-
- `switchboard.shimmy(device, -1)` — shimmy a device backward one station
|
|
280
|
-
- `switchboard.connect(device, p4)` — connect-or-reassign a device to a specific station
|
|
281
|
-
- `switchboard.connect(device)` — connect a device to the next unassigned station (or the last station)
|
|
282
|
-
- `switchboard.disconnect(device)` — unassign a device and forget about it
|
|
341
|
+
|
|
283
342
|
|
|
284
343
|
<br/><br/>
|
|
285
344
|
|
|
286
345
|
## 🍋 tact nubs
|
|
287
|
-
> mobile ui like virtual thumbsticks and buttons
|
|
346
|
+
> *mobile ui like virtual thumbsticks and buttons*
|
|
288
347
|
|
|
289
|
-
###
|
|
348
|
+
### 📱 nub stick
|
|
290
349
|
> TODO lol need to write docs
|
|
291
350
|
|
|
292
|
-
###
|
|
351
|
+
### 📱 nub virtual gamepad
|
|
293
352
|
> TODO lol need to write docs
|
|
294
353
|
|
|
354
|
+
|
|
355
|
+
|
|
295
356
|
<br/><br/>
|
|
296
357
|
|
|
297
358
|
## 🍋 tact is by https://benevolent.games/
|
|
298
|
-
> building the future of web games
|
|
359
|
+
> *building the future of web games*
|
|
299
360
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benev/tact",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-2",
|
|
4
4
|
"description": "keybindings and gamepad support for web games",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"main": "./x/index.js",
|
|
9
9
|
"sideEffects": false,
|
|
10
10
|
"exports": {
|
|
11
|
-
".": "./x/index.js"
|
|
11
|
+
".": "./x/index.js",
|
|
12
|
+
"./core": "./x/core/index.js"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"x",
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
import {Action} from "./parts/action.js"
|
|
3
|
-
|
|
4
|
-
export type Actions<B extends Bindings> = {
|
|
5
|
-
[Mode in keyof B]: {
|
|
6
|
-
[K in keyof B[Mode]]: Action
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type Sample = [code: string, value: number]
|
|
11
|
-
export type SampleMap = Map<string, number>
|
|
12
|
-
|
|
13
2
|
export type Timing = (
|
|
14
3
|
| DirectTiming
|
|
15
4
|
| TapTiming
|
|
@@ -32,11 +21,6 @@ export type Lens = {
|
|
|
32
21
|
settings?: Partial<LensSettings>
|
|
33
22
|
}
|
|
34
23
|
|
|
35
|
-
export type LensState = {
|
|
36
|
-
lastValue: number
|
|
37
|
-
holdStart: number
|
|
38
|
-
}
|
|
39
|
-
|
|
40
24
|
export type Spoon = {
|
|
41
25
|
lenses: Lens[]
|
|
42
26
|
required?: Lens[]
|
|
@@ -59,14 +43,14 @@ export function asBindings<B extends Bindings>(bindings: B) {
|
|
|
59
43
|
return bindings
|
|
60
44
|
}
|
|
61
45
|
|
|
62
|
-
export const
|
|
46
|
+
export const hubMode = "hub" as const
|
|
63
47
|
|
|
64
|
-
export type
|
|
65
|
-
[
|
|
48
|
+
export type AsHubBindings<B extends Bindings> = {
|
|
49
|
+
[hubMode]: {
|
|
66
50
|
shimmyNext: Spoon[],
|
|
67
51
|
shimmyPrevious: Spoon[],
|
|
68
52
|
}
|
|
69
53
|
} & B
|
|
70
54
|
|
|
71
|
-
export type
|
|
55
|
+
export type HubBindings = AsHubBindings<Bindings>
|
|
72
56
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import {SetG} from "@e280/stz"
|
|
3
|
+
import {Controller} from "../controller.js"
|
|
4
|
+
|
|
5
|
+
export class GroupController extends Controller {
|
|
6
|
+
controllers = new SetG<Controller>()
|
|
7
|
+
|
|
8
|
+
constructor(...controllers: Controller[]) {
|
|
9
|
+
super()
|
|
10
|
+
this.controllers.adds(...controllers)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
takeSamples() {
|
|
14
|
+
return [...this.controllers].flatMap(controller => controller.takeSamples())
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import {sub} from "@e280/stz"
|
|
3
|
-
import {
|
|
4
|
-
import {Sample, SampleMap} from "
|
|
3
|
+
import {Controller} from "../controller.js"
|
|
4
|
+
import {Sample, SampleMap} from "../types.js"
|
|
5
5
|
|
|
6
|
-
export class
|
|
6
|
+
export class SamplerController extends Controller {
|
|
7
7
|
on = sub<Sample>()
|
|
8
8
|
#map: SampleMap = new Map()
|
|
9
9
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import {tmax} from "
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {gamepads, Pad} from "
|
|
2
|
+
import {tmax} from "../../../utils/quick-math.js"
|
|
3
|
+
import {splitAxis} from "../../../utils/split-axis.js"
|
|
4
|
+
import {SamplerController} from "../infra/sampler.js"
|
|
5
|
+
import {gamepads, Pad} from "../../../utils/gamepads.js"
|
|
6
6
|
|
|
7
7
|
const gamepadButtonCodes = [
|
|
8
8
|
"gamepad.a",
|
|
@@ -24,8 +24,8 @@ const gamepadButtonCodes = [
|
|
|
24
24
|
"gamepad.gamma",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
|
-
export class
|
|
28
|
-
static on(fn: (
|
|
27
|
+
export class GamepadController extends SamplerController {
|
|
28
|
+
static on(fn: (controller: GamepadController) => () => void) {
|
|
29
29
|
return gamepads(pad => fn(new this(pad)))
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
import {coalesce, ev, sub} from "@e280/stz"
|
|
3
3
|
import {Sample} from "../types.js"
|
|
4
|
-
import {
|
|
4
|
+
import {Controller} from "../controller.js"
|
|
5
5
|
import {modprefix} from "../utils/modprefix.js"
|
|
6
6
|
|
|
7
|
-
export class
|
|
7
|
+
export class KeyboardController extends Controller {
|
|
8
8
|
on = sub<Sample>()
|
|
9
9
|
dispose: () => void
|
|
10
10
|
#held = new Set<string>()
|
|
11
11
|
|
|
12
|
-
constructor(target: EventTarget) {
|
|
12
|
+
constructor(target: EventTarget = window) {
|
|
13
13
|
super()
|
|
14
14
|
|
|
15
15
|
const down = (code: string) => {
|