@edv4h/usketch-plugin-character 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -11
- package/dist/character-input.d.ts +11 -3
- package/dist/character-input.d.ts.map +1 -1
- package/dist/character-input.js +63 -18
- package/dist/character-input.js.map +1 -1
- package/dist/character-key-choices.d.ts +14 -0
- package/dist/character-key-choices.d.ts.map +1 -0
- package/dist/character-key-choices.js +23 -0
- package/dist/character-key-choices.js.map +1 -0
- package/dist/character-layer.d.ts +1 -1
- package/dist/character-layer.d.ts.map +1 -1
- package/dist/character-layer.js +45 -14
- package/dist/character-layer.js.map +1 -1
- package/dist/character-physics.d.ts +156 -2
- package/dist/character-physics.d.ts.map +1 -1
- package/dist/character-physics.js +270 -22
- package/dist/character-physics.js.map +1 -1
- package/dist/character-runtime.d.ts +8 -1
- package/dist/character-runtime.d.ts.map +1 -1
- package/dist/character-runtime.js +90 -8
- package/dist/character-runtime.js.map +1 -1
- package/dist/character-service.d.ts +23 -3
- package/dist/character-service.d.ts.map +1 -1
- package/dist/character-service.js +7 -0
- package/dist/character-service.js.map +1 -1
- package/dist/character-store.d.ts +34 -1
- package/dist/character-store.d.ts.map +1 -1
- package/dist/character-store.js +86 -4
- package/dist/character-store.js.map +1 -1
- package/dist/character-sync.d.ts +11 -1
- package/dist/character-sync.d.ts.map +1 -1
- package/dist/character-sync.js +23 -1
- package/dist/character-sync.js.map +1 -1
- package/dist/character-types.d.ts +31 -2
- package/dist/character-types.d.ts.map +1 -1
- package/dist/character-types.js +2 -1
- package/dist/character-types.js.map +1 -1
- package/dist/character-virtual-input.d.ts +36 -0
- package/dist/character-virtual-input.d.ts.map +1 -0
- package/dist/character-virtual-input.js +48 -0
- package/dist/character-virtual-input.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +13 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/dist/plugin.js.map +1 -1
- package/dist/register-character-hud.d.ts.map +1 -1
- package/dist/register-character-hud.js +88 -1
- package/dist/register-character-hud.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,7 +23,9 @@ createCharacterPlugin({
|
|
|
23
23
|
keys: { up: ["KeyW", "ArrowUp"] }, // KeyboardEvent.code values
|
|
24
24
|
cameraMode: "rotate", // "fixed" | "rotate" | "free"
|
|
25
25
|
controlScheme: "vehicle", // "directional" | "vehicle"
|
|
26
|
-
drift: true, // vehicle:
|
|
26
|
+
drift: true, // vehicle: Shift + steer drifts (or tuning overrides)
|
|
27
|
+
jump: true, // Space jumps (or tuning overrides)
|
|
28
|
+
renderShadow: ({ altitude }) => <div className="shadow" style={{ scale: 1 / (1 + altitude / 60) }} />,
|
|
27
29
|
screenAnchor: { x: 0.5, y: 0.75 },
|
|
28
30
|
});
|
|
29
31
|
```
|
|
@@ -34,7 +36,9 @@ createCharacterPlugin({
|
|
|
34
36
|
as CSS `rotate()` and the viewport `rotation`.
|
|
35
37
|
- **Render props**: `heading` (world), `screenHeading` (= `heading + viewport.rotation`,
|
|
36
38
|
what to rotate a top-down sprite by), `moving`, `speed`, `steering`, `slip`,
|
|
37
|
-
`drifting`, `zoom`, `appearance`, `name`, `isSelf`, `id`, `elevation
|
|
39
|
+
`drifting`, `zoom`, `appearance`, `name`, `isSelf`, `id`, `elevation`, `z`, `altitude`,
|
|
40
|
+
`airborne`, `verticalSpeed`, `hovering`, `hoverGauge` (0 … 1, `null` with hovering
|
|
41
|
+
off). Each character is placed centered on its screen position
|
|
38
42
|
in one screen-space layer, so self and remote characters look the same under zoom
|
|
39
43
|
and camera rotation.
|
|
40
44
|
- **Control schemes**
|
|
@@ -44,7 +48,7 @@ createCharacterPlugin({
|
|
|
44
48
|
- `vehicle` — up/down throttle and reverse, left/right steer. Steering scales
|
|
45
49
|
with speed (a stopped car can't turn) and inverts in reverse. The held steering
|
|
46
50
|
(-1 … 1) is in the pose and render props, e.g. to turn the front wheels.
|
|
47
|
-
- **Drift** (`vehicle`, opt-in via `drift`): hold the drift key (
|
|
51
|
+
- **Drift** (`vehicle`, opt-in via `drift`): hold the drift key (Shift) and steer at
|
|
48
52
|
speed to start an arcade drift toward the steering. It turns tighter than normal
|
|
49
53
|
steering and slides the body by `slip` degrees (draw the car at `heading + slip`;
|
|
50
54
|
it keeps traveling along `heading`). Steering into the drift tightens it,
|
|
@@ -52,7 +56,38 @@ createCharacterPlugin({
|
|
|
52
56
|
`stopSpeed` or reversing ends it, and the slip eases back. Tuning (`DriftParams`):
|
|
53
57
|
`startSpeed` / `stopSpeed` (fractions of `moveSpeed`), `turnRate` / `steerRate`
|
|
54
58
|
(multiples of `turnRate`), `slipAngle` / `steerSlipAngle` (degrees), `recoveryRate`
|
|
55
|
-
(1/s).
|
|
59
|
+
(1/s). With `hop: true`, pressing the drift key on the ground hops `hopHeight`
|
|
60
|
+
(default 10) first, and the drift starts on landing if the key is still held and
|
|
61
|
+
steering (a car can't steer in the air). The drift key is only captured while drift
|
|
62
|
+
is on.
|
|
63
|
+
- **Jump** (opt-in via `jump`): press the jump key (Space) to jump. The arc is set by
|
|
64
|
+
its apex `height` (world units) and `timeToApex`; it falls `fallGravity` × faster than
|
|
65
|
+
it rises, releasing the key while rising cuts it short (`releaseCut`), a press within
|
|
66
|
+
`bufferTime` before landing jumps on touchdown, and a jump within `coyoteTime` of
|
|
67
|
+
walking off a ledge still counts. The pose carries the feet height `z` (absolute, like
|
|
68
|
+
the ground height), `vz` and `airborne`. Where the jump key is also the active drift
|
|
69
|
+
key (both can be rebound) the drift wins. `api.jump()` (and the HUD
|
|
70
|
+
action) jumps from code, as a full jump.
|
|
71
|
+
- **Multi-jump** (`jump.airJumps`, default 0): a fresh press in the air uses one of
|
|
72
|
+
`airJumps` extra jumps while any remain (1 = a double jump); each reaches
|
|
73
|
+
`airJumpRatio` (default 0.8) × `height` (take-off speed × √ratio). They come back on
|
|
74
|
+
landing.
|
|
75
|
+
- **Hover** (`jump.hover`, default off; `true` or a partial `HoverParams`): once the air
|
|
76
|
+
jumps are used up (or there are none), holding the jump key while falling fires a
|
|
77
|
+
thrust and drains a gauge that lasts `duration` (1.5 s); an empty gauge falls normally.
|
|
78
|
+
`thrust` is a multiple of gravity (default 0 = a glide): below 1 the character sinks,
|
|
79
|
+
at 1 it keeps its vertical speed, above 1 it climbs for as long as the key is held.
|
|
80
|
+
Sinking is capped at `fallSpeed` (default 15 world units / s, 0 = never sink), climbing
|
|
81
|
+
at `riseSpeed` (60). The gauge refills
|
|
82
|
+
on the ground over `rechargeTime` (0.8 s), not at once on landing. The pose carries
|
|
83
|
+
`hovering` and `hoverGauge` (stays 1 with hovering off); both are broadcast.
|
|
84
|
+
- **Keys**: the jump (Space) and the drift (Shift) have their own keys. The HUD offers
|
|
85
|
+
a few keys for each (`KEY_CHOICES`: Space, Shift, Z, X, C, J, K, L); `setKeys` takes
|
|
86
|
+
any `KeyboardEvent.code`s and `getKeys` returns the bindings.
|
|
87
|
+
- **Shadow**: pass `renderShadow` to draw a shadow; it is placed on the ground under
|
|
88
|
+
each character while the body stands at its feet height `z`, so under a 3D view
|
|
89
|
+
(Mode 7) a jump lifts the body off its shadow. `altitude` (`z - elevation`) lets it
|
|
90
|
+
shrink as the character rises.
|
|
56
91
|
- **Keyboard focus**: movement keys are captured on `window` while the character is
|
|
57
92
|
on, except where the page needs them: nothing is taken while a text field has focus
|
|
58
93
|
or focus is inside a dialog / menu (`dialog`, `role="dialog"`, `alertdialog`, `menu`;
|
|
@@ -62,6 +97,17 @@ createCharacterPlugin({
|
|
|
62
97
|
driving, and Space is left to buttons, links and other controls it activates. Focus
|
|
63
98
|
is read through `composedPath()`, so web-component dialogs count too. Moving focus
|
|
64
99
|
to such a target releases the held keys it uses.
|
|
100
|
+
- **Touch / gamepad (virtual input)**: a host control feeds analog input with
|
|
101
|
+
`api.setVirtualInput({ throttle, steer, drift })` (`throttle` / `steer` in -1 … 1;
|
|
102
|
+
`directional` reads them as screen up / right). Send the current state on every
|
|
103
|
+
change and `null` on release. It adds to the held keys (capped at ±1), so keyboard
|
|
104
|
+
and stick can drive together; a partial `throttle` aims for that fraction of the top
|
|
105
|
+
speed and a partial `steer` turns by that fraction. Touching it resumes a paused
|
|
106
|
+
follow camera like a movement key. It is ignored while the character is off, and
|
|
107
|
+
turning the character off releases it. `jump: true` is the jump button: held like the
|
|
108
|
+
jump key (release while rising for a short hop, hold in a fall to hover), and a press
|
|
109
|
+
between two frames still counts. A `drift` press also starts a drift hop when
|
|
110
|
+
`drift.hop` is on.
|
|
65
111
|
- **Camera modes**
|
|
66
112
|
- `fixed` — follow, world stays upright.
|
|
67
113
|
- `rotate` — follow and turn the world by `-heading` (character always faces up).
|
|
@@ -78,8 +124,11 @@ createCharacterPlugin({
|
|
|
78
124
|
`@edv4h/usketch-shared`, e.g. the map plugin's raised terrain), moving onto
|
|
79
125
|
ground more than `motion.maxStep` (default 24 world units, HUD "登れる段差") higher
|
|
80
126
|
than where the character stands is blocked; it slides along the cliff instead.
|
|
81
|
-
|
|
82
|
-
|
|
127
|
+
The step is measured from the feet, so mid-jump taller cliffs are reachable; a ledge
|
|
128
|
+
within the step above the feet is landed on. Stepping down within the step snaps
|
|
129
|
+
down; a bigger drop falls (gravity applies even with jumping off). The render props
|
|
130
|
+
carry `elevation` (the ground) and `z` (the feet), and under a 3D view (Mode 7) the
|
|
131
|
+
character is lifted to its feet height.
|
|
83
132
|
- **Input**: held keys are tracked from window `keydown`/`keyup` (capture phase,
|
|
84
133
|
`event.code`), swallowed while the character is on so single-letter tool
|
|
85
134
|
shortcuts don't fire. Typing in text fields, and key chords with Ctrl/Cmd/Alt,
|
|
@@ -87,9 +136,9 @@ createCharacterPlugin({
|
|
|
87
136
|
|
|
88
137
|
## HUD
|
|
89
138
|
|
|
90
|
-
A "キャラクター" settings group (on/off, camera, scheme, drift,
|
|
91
|
-
climbable step, screen position, camera lag) plus actions to toggle the
|
|
92
|
-
screen position.
|
|
139
|
+
A "キャラクター" settings group (on/off, camera, scheme, drift, drift key, drift hop, jump, jump key, jump height, air
|
|
140
|
+
jumps, hover, hover time, hover thrust, speed, turn rate, climbable step, screen position, camera lag) plus actions to toggle the
|
|
141
|
+
character, to place it at the screen position, and to jump.
|
|
93
142
|
|
|
94
143
|
## Service
|
|
95
144
|
|
|
@@ -100,8 +149,15 @@ const api = getCharacterApi(app.services);
|
|
|
100
149
|
api?.enable();
|
|
101
150
|
api?.setCameraMode("rotate");
|
|
102
151
|
api?.setRenderer(myRenderer);
|
|
103
|
-
api?.setDrift({ slipAngle: 35 }); // true / false / tuning overrides
|
|
104
|
-
api?.
|
|
152
|
+
api?.setDrift({ slipAngle: 35, hop: true }); // true / false / tuning overrides
|
|
153
|
+
api?.setJump({ height: 60 }); // true / false / tuning overrides
|
|
154
|
+
api?.setJump({ airJumps: 1, hover: { duration: 2 } }); // double jump + hover (hover: true / false / partial)
|
|
155
|
+
api?.jump();
|
|
156
|
+
api?.setKeys({ ...api.getKeys(), drift: ["KeyX"] }); // KeyboardEvent.code values
|
|
157
|
+
api?.setShadowRenderer(myShadow);
|
|
158
|
+
api?.getPose(); // { x, y, heading, speed, moving, steering, slip, drift, z, vz, airborne, hovering, hoverGauge }
|
|
159
|
+
api?.setVirtualInput({ throttle: 0.8, steer: -0.3 }); // touch stick; null on release
|
|
160
|
+
api?.setVirtualInput({ throttle: 0.8, steer: 0, jump: true }); // + jump button held
|
|
105
161
|
```
|
|
106
162
|
|
|
107
163
|
## Limitations
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { MoveInput } from "./character-physics.js";
|
|
2
2
|
import type { CharacterKeys } from "./character-types.js";
|
|
3
3
|
export interface KeyInput {
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* The currently held directions (and the drift / jump keys). `jumpPressed` /
|
|
6
|
+
* `driftPressed` report a press since the previous `read()`, so a tap between two
|
|
7
|
+
* frames isn't lost.
|
|
8
|
+
*/
|
|
5
9
|
read(): MoveInput;
|
|
10
|
+
/** The current key bindings. */
|
|
11
|
+
getKeys(): CharacterKeys;
|
|
6
12
|
/** Whether any bound key is held. */
|
|
7
13
|
anyHeld(): boolean;
|
|
8
14
|
/** Replace the key bindings (held state is cleared). */
|
|
@@ -13,11 +19,13 @@ export interface KeyInput {
|
|
|
13
19
|
* Listen for the bound keys on `window`. `isActive()` gates everything: while it is
|
|
14
20
|
* false no key is captured (and none is swallowed). Keys are left alone while focus is
|
|
15
21
|
* in a text field or inside a dialog / menu, arrow keys while a widget that uses them
|
|
16
|
-
* (slider, radio, tab …) has focus, and the drift
|
|
22
|
+
* (slider, radio, tab …) has focus, and the drift / jump keys on controls Space activates.
|
|
17
23
|
* Held keys are cleared on window blur and tab hide, and released when focus moves to
|
|
18
24
|
* a target that uses them, so a key released elsewhere can't get stuck "down".
|
|
19
25
|
*/
|
|
20
26
|
export declare function createKeyInput(initialKeys: CharacterKeys, isActive: () => boolean,
|
|
21
27
|
/** Whether the drift key does anything now (else it is left to the host, e.g. Space-pan). */
|
|
22
|
-
isDriftActive?: () => boolean
|
|
28
|
+
isDriftActive?: () => boolean,
|
|
29
|
+
/** Whether the jump key does anything now (else it is left to the host). */
|
|
30
|
+
isJumpActive?: () => boolean): KeyInput;
|
|
23
31
|
//# sourceMappingURL=character-input.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"character-input.d.ts","sourceRoot":"","sources":["../src/character-input.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACxB
|
|
1
|
+
{"version":3,"file":"character-input.d.ts","sourceRoot":"","sources":["../src/character-input.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACxB;;;;OAIG;IACH,IAAI,IAAI,SAAS,CAAC;IAClB,gCAAgC;IAChC,OAAO,IAAI,aAAa,CAAC;IACzB,qCAAqC;IACrC,OAAO,IAAI,OAAO,CAAC;IACnB,wDAAwD;IACxD,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,OAAO,IAAI,IAAI,CAAC;CAChB;AAkJD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC7B,WAAW,EAAE,aAAa,EAC1B,QAAQ,EAAE,MAAM,OAAO;AACvB,6FAA6F;AAC7F,aAAa,GAAE,MAAM,OAAqB;AAC1C,4EAA4E;AAC5E,YAAY,GAAE,MAAM,OAAqB,GACvC,QAAQ,CAkIV"}
|
package/dist/character-input.js
CHANGED
|
@@ -46,7 +46,7 @@ function focusPath(e) {
|
|
|
46
46
|
return chain;
|
|
47
47
|
}
|
|
48
48
|
const roleOf = (el) => el && typeof el.getAttribute === "function" ? el.getAttribute("role") : null;
|
|
49
|
-
/** Elements Space activates (or types into): the drift
|
|
49
|
+
/** Elements Space activates (or types into): the drift and jump keys must not steal it from them. */
|
|
50
50
|
function isSpaceTarget(el) {
|
|
51
51
|
if (!el)
|
|
52
52
|
return false;
|
|
@@ -129,16 +129,24 @@ function isTextInput(el) {
|
|
|
129
129
|
* Listen for the bound keys on `window`. `isActive()` gates everything: while it is
|
|
130
130
|
* false no key is captured (and none is swallowed). Keys are left alone while focus is
|
|
131
131
|
* in a text field or inside a dialog / menu, arrow keys while a widget that uses them
|
|
132
|
-
* (slider, radio, tab …) has focus, and the drift
|
|
132
|
+
* (slider, radio, tab …) has focus, and the drift / jump keys on controls Space activates.
|
|
133
133
|
* Held keys are cleared on window blur and tab hide, and released when focus moves to
|
|
134
134
|
* a target that uses them, so a key released elsewhere can't get stuck "down".
|
|
135
135
|
*/
|
|
136
136
|
export function createKeyInput(initialKeys, isActive,
|
|
137
137
|
/** Whether the drift key does anything now (else it is left to the host, e.g. Space-pan). */
|
|
138
|
-
isDriftActive = () => false
|
|
138
|
+
isDriftActive = () => false,
|
|
139
|
+
/** Whether the jump key does anything now (else it is left to the host). */
|
|
140
|
+
isJumpActive = () => false) {
|
|
139
141
|
let keys = initialKeys;
|
|
140
142
|
/** Held codes → the `key` they produced (to tell numpad arrows from digits). */
|
|
141
143
|
const held = new Map();
|
|
144
|
+
/** Held codes that act as the jump key (bound when pressed, so a rebind can't strand one). */
|
|
145
|
+
const jumpHeld = new Set();
|
|
146
|
+
let jumpPressed = false;
|
|
147
|
+
/** Held codes that act as the drift key (as for the jump). */
|
|
148
|
+
const driftHeld = new Set();
|
|
149
|
+
let driftPressed = false;
|
|
142
150
|
const directionOf = (code) => {
|
|
143
151
|
for (const dir of ["up", "down", "left", "right"]) {
|
|
144
152
|
if (keys[dir].includes(code))
|
|
@@ -146,8 +154,12 @@ isDriftActive = () => false) {
|
|
|
146
154
|
}
|
|
147
155
|
if (keys.drift?.includes(code) && isDriftActive())
|
|
148
156
|
return "drift";
|
|
157
|
+
if (keys.jump?.includes(code) && isJumpActive())
|
|
158
|
+
return "jump";
|
|
149
159
|
return null;
|
|
150
160
|
};
|
|
161
|
+
/** Keys Space activates on buttons etc.: the drift and jump keys yield to those. */
|
|
162
|
+
const isSpaceLike = (code) => (keys.drift?.includes(code) ?? false) || (keys.jump?.includes(code) ?? false);
|
|
151
163
|
const onKeyDown = (e) => {
|
|
152
164
|
if (!isActive())
|
|
153
165
|
return;
|
|
@@ -159,21 +171,43 @@ isDriftActive = () => false) {
|
|
|
159
171
|
const path = focusPath(e);
|
|
160
172
|
if (blocksAllKeys(path))
|
|
161
173
|
return;
|
|
162
|
-
if (dir === "drift" && isSpaceTarget(path[0]))
|
|
174
|
+
if ((dir === "drift" || dir === "jump") && isSpaceTarget(path[0]))
|
|
163
175
|
return;
|
|
164
176
|
if (isArrowKey(e.code, e.key) && isArrowTarget(path[0]))
|
|
165
177
|
return;
|
|
166
178
|
held.set(e.code, e.key ?? "");
|
|
179
|
+
if (dir === "jump") {
|
|
180
|
+
// Auto-repeat keydowns are not new presses.
|
|
181
|
+
if (!e.repeat && !jumpHeld.has(e.code))
|
|
182
|
+
jumpPressed = true;
|
|
183
|
+
jumpHeld.add(e.code);
|
|
184
|
+
}
|
|
185
|
+
else if (dir === "drift") {
|
|
186
|
+
if (!e.repeat && !driftHeld.has(e.code))
|
|
187
|
+
driftPressed = true;
|
|
188
|
+
driftHeld.add(e.code);
|
|
189
|
+
}
|
|
167
190
|
e.preventDefault();
|
|
168
191
|
e.stopImmediatePropagation();
|
|
169
192
|
};
|
|
193
|
+
const release = (code) => {
|
|
194
|
+
jumpHeld.delete(code);
|
|
195
|
+
driftHeld.delete(code);
|
|
196
|
+
return held.delete(code);
|
|
197
|
+
};
|
|
170
198
|
const onKeyUp = (e) => {
|
|
171
|
-
if (!
|
|
199
|
+
if (!release(e.code))
|
|
172
200
|
return;
|
|
173
201
|
e.preventDefault();
|
|
174
202
|
e.stopImmediatePropagation();
|
|
175
203
|
};
|
|
176
|
-
const clear = () =>
|
|
204
|
+
const clear = () => {
|
|
205
|
+
held.clear();
|
|
206
|
+
jumpHeld.clear();
|
|
207
|
+
jumpPressed = false;
|
|
208
|
+
driftHeld.clear();
|
|
209
|
+
driftPressed = false;
|
|
210
|
+
};
|
|
177
211
|
const onVisibility = () => {
|
|
178
212
|
if (typeof document !== "undefined" && document.hidden)
|
|
179
213
|
clear();
|
|
@@ -188,9 +222,9 @@ isDriftActive = () => false) {
|
|
|
188
222
|
return;
|
|
189
223
|
}
|
|
190
224
|
const owned = [...held].filter(([code, key]) => (isArrowKey(code, key) && isArrowTarget(path[0])) ||
|
|
191
|
-
((
|
|
225
|
+
(isSpaceLike(code) && isSpaceTarget(path[0])));
|
|
192
226
|
for (const [code] of owned)
|
|
193
|
-
|
|
227
|
+
release(code);
|
|
194
228
|
};
|
|
195
229
|
const hasWindow = typeof window !== "undefined";
|
|
196
230
|
if (hasWindow) {
|
|
@@ -202,18 +236,29 @@ isDriftActive = () => false) {
|
|
|
202
236
|
}
|
|
203
237
|
const isHeld = (dir) => keys[dir]?.some((c) => held.has(c)) ?? false;
|
|
204
238
|
return {
|
|
205
|
-
read: () =>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
239
|
+
read: () => {
|
|
240
|
+
const pressed = jumpPressed;
|
|
241
|
+
jumpPressed = false;
|
|
242
|
+
const drifted = driftPressed && isDriftActive();
|
|
243
|
+
driftPressed = false;
|
|
244
|
+
return {
|
|
245
|
+
up: isHeld("up"),
|
|
246
|
+
down: isHeld("down"),
|
|
247
|
+
left: isHeld("left"),
|
|
248
|
+
right: isHeld("right"),
|
|
249
|
+
// A key bound to both acts as the drift while drift is on (directionOf).
|
|
250
|
+
drift: isDriftActive() && isHeld("drift"),
|
|
251
|
+
jump: jumpHeld.size > 0,
|
|
252
|
+
jumpPressed: pressed,
|
|
253
|
+
driftPressed: drifted,
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
getKeys: () => keys,
|
|
212
257
|
anyHeld: () => held.size > 0,
|
|
213
258
|
setKeys(next) {
|
|
214
|
-
// Rebinding movement keeps the drift
|
|
215
|
-
keys = { ...next, drift: next.drift ?? keys.drift };
|
|
216
|
-
|
|
259
|
+
// Rebinding movement keeps the drift / jump keys unless given (`[]` unbinds).
|
|
260
|
+
keys = { ...next, drift: next.drift ?? keys.drift, jump: next.jump ?? keys.jump };
|
|
261
|
+
clear();
|
|
217
262
|
},
|
|
218
263
|
dispose() {
|
|
219
264
|
if (!hasWindow)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"character-input.js","sourceRoot":"","sources":["../src/character-input.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"character-input.js","sourceRoot":"","sources":["../src/character-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CharacterKeys } from "./character-types.js";
|
|
2
|
+
export interface KeyChoice {
|
|
3
|
+
/** HUD option value. */
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** `KeyboardEvent.code` values it binds. */
|
|
7
|
+
codes: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export declare const KEY_CHOICES: readonly KeyChoice[];
|
|
10
|
+
/** The choice whose codes are exactly `codes` (in any order), or `null`. */
|
|
11
|
+
export declare function keyChoiceOf(codes: readonly string[] | undefined): KeyChoice | null;
|
|
12
|
+
/** `keys` with the jump or drift key set to the choice `value` (unchanged for an unknown one). */
|
|
13
|
+
export declare function withKeyChoice(keys: CharacterKeys, action: "jump" | "drift", value: string): CharacterKeys;
|
|
14
|
+
//# sourceMappingURL=character-key-choices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-key-choices.d.ts","sourceRoot":"","sources":["../src/character-key-choices.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,SAAS;IACzB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAS3C,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,CAMlF;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAC5B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,GAAG,OAAO,EACxB,KAAK,EAAE,MAAM,GACX,aAAa,CAGf"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const KEY_CHOICES = [
|
|
2
|
+
{ value: "space", label: "Space", codes: ["Space"] },
|
|
3
|
+
{ value: "shift", label: "Shift", codes: ["ShiftLeft", "ShiftRight"] },
|
|
4
|
+
{ value: "z", label: "Z", codes: ["KeyZ"] },
|
|
5
|
+
{ value: "x", label: "X", codes: ["KeyX"] },
|
|
6
|
+
{ value: "c", label: "C", codes: ["KeyC"] },
|
|
7
|
+
{ value: "j", label: "J", codes: ["KeyJ"] },
|
|
8
|
+
{ value: "k", label: "K", codes: ["KeyK"] },
|
|
9
|
+
{ value: "l", label: "L", codes: ["KeyL"] },
|
|
10
|
+
];
|
|
11
|
+
/** The choice whose codes are exactly `codes` (in any order), or `null`. */
|
|
12
|
+
export function keyChoiceOf(codes) {
|
|
13
|
+
if (!codes)
|
|
14
|
+
return null;
|
|
15
|
+
const set = new Set(codes);
|
|
16
|
+
return (KEY_CHOICES.find((c) => c.codes.length === set.size && c.codes.every((k) => set.has(k))) ?? null);
|
|
17
|
+
}
|
|
18
|
+
/** `keys` with the jump or drift key set to the choice `value` (unchanged for an unknown one). */
|
|
19
|
+
export function withKeyChoice(keys, action, value) {
|
|
20
|
+
const choice = KEY_CHOICES.find((c) => c.value === value);
|
|
21
|
+
return choice ? { ...keys, [action]: [...choice.codes] } : keys;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=character-key-choices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-key-choices.js","sourceRoot":"","sources":["../src/character-key-choices.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,WAAW,GAAyB;IAChD,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE;IACpD,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE;IACtE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3C,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3C,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3C,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3C,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;IAC3C,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE;CAC3C,CAAC;AAEF,4EAA4E;AAC5E,MAAM,UAAU,WAAW,CAAC,KAAoC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,CACN,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAChG,CAAC;AACH,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAC5B,IAAmB,EACnB,MAAwB,EACxB,KAAa;IAEb,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Viewport } from "@edv4h/usketch-shared";
|
|
2
2
|
import type { HeightAt } from "./character-physics.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type CharacterStore } from "./character-store.js";
|
|
4
4
|
export declare function CharacterLayer({ store, viewport, heightAt, }: {
|
|
5
5
|
store: CharacterStore;
|
|
6
6
|
viewport: Viewport;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"character-layer.d.ts","sourceRoot":"","sources":["../src/character-layer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"character-layer.d.ts","sourceRoot":"","sources":["../src/character-layer.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,QAAQ,EAA4C,MAAM,uBAAuB,CAAC;AAEhG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,sBAAsB,CAAC;AA6CzE,wBAAgB,cAAc,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,QAAQ,GACR,EAAE;IACF,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACpB,sCA4GA"}
|
package/dist/character-layer.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// The one fixed (screen-space) layer that places every character — self and remote
|
|
3
3
|
// — at `worldToScreen(position)`. It draws NOTHING itself: each spot is a zero-size,
|
|
4
4
|
// pointer-transparent wrapper whose content is the host's `renderCharacter`. One
|
|
5
5
|
// screen-space layer keeps self/remote consistent (same size under zoom, same
|
|
6
|
-
// `screenHeading` math under camera rotation).
|
|
6
|
+
// `screenHeading` math under camera rotation). The optional `renderShadow` gets a spot
|
|
7
|
+
// of its own on the GROUND under each character, while the body stands at its feet
|
|
8
|
+
// height — under a 3D view (Mode 7) a jump lifts the body off its shadow.
|
|
7
9
|
import { viewportRotation, worldToScreen, wrapDeg } from "@edv4h/usketch-shared";
|
|
8
10
|
import { useSyncExternalStore } from "react";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
import { hoverGaugeOf } from "./character-store.js";
|
|
12
|
+
/** Screen px a shadow floats above its ground, so it doesn't z-fight a raised terrain top. */
|
|
13
|
+
const SHADOW_LIFT_PX = 0.5;
|
|
14
|
+
function Spot({ shadow = false, x, y, lift, renderer, props, }) {
|
|
15
|
+
return (_jsx("div", { "data-character-id": shadow ? undefined : props.id, "data-character-shadow": shadow ? props.id : undefined, style: {
|
|
11
16
|
position: "absolute",
|
|
12
17
|
left: x,
|
|
13
18
|
top: y,
|
|
@@ -22,12 +27,15 @@ export function CharacterLayer({ store, viewport, heightAt, }) {
|
|
|
22
27
|
const renderer = store.getRenderer();
|
|
23
28
|
if (!renderer)
|
|
24
29
|
return null; // headless: no look supplied → draw nothing
|
|
30
|
+
const shadowRenderer = store.getShadowRenderer();
|
|
25
31
|
const rot = viewportRotation(viewport);
|
|
26
|
-
const
|
|
32
|
+
const bodies = [];
|
|
27
33
|
for (const r of state.remotes.values()) {
|
|
28
|
-
const p = worldToScreen(r.x, r.y, viewport);
|
|
29
34
|
const elevation = heightAt?.(r.x, r.y) ?? 0;
|
|
30
|
-
|
|
35
|
+
const z = Math.max(elevation, r.z ?? elevation);
|
|
36
|
+
bodies.push({
|
|
37
|
+
at: worldToScreen(r.x, r.y, viewport),
|
|
38
|
+
props: {
|
|
31
39
|
id: r.id,
|
|
32
40
|
isSelf: false,
|
|
33
41
|
heading: r.heading,
|
|
@@ -41,14 +49,24 @@ export function CharacterLayer({ store, viewport, heightAt, }) {
|
|
|
41
49
|
appearance: r.appearance,
|
|
42
50
|
name: r.name,
|
|
43
51
|
elevation,
|
|
44
|
-
|
|
52
|
+
z,
|
|
53
|
+
altitude: z - elevation,
|
|
54
|
+
airborne: r.airborne,
|
|
55
|
+
verticalSpeed: r.vz,
|
|
56
|
+
hovering: r.hovering,
|
|
57
|
+
hoverGauge: r.hoverGauge,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
45
60
|
}
|
|
46
61
|
if (state.enabled && state.spawned) {
|
|
47
62
|
const { pose } = state;
|
|
48
|
-
const p = worldToScreen(pose.x, pose.y, viewport);
|
|
49
63
|
const elevation = heightAt?.(pose.x, pose.y) ?? 0;
|
|
64
|
+
// Before the first vertical step a fresh spawn's `z` may still be below the ground.
|
|
65
|
+
const z = Math.max(elevation, pose.z);
|
|
50
66
|
// Self last → drawn on top of the others.
|
|
51
|
-
|
|
67
|
+
bodies.push({
|
|
68
|
+
at: worldToScreen(pose.x, pose.y, viewport),
|
|
69
|
+
props: {
|
|
52
70
|
id: "self",
|
|
53
71
|
isSelf: true,
|
|
54
72
|
heading: pose.heading,
|
|
@@ -62,15 +80,28 @@ export function CharacterLayer({ store, viewport, heightAt, }) {
|
|
|
62
80
|
appearance: state.appearance,
|
|
63
81
|
name: state.name,
|
|
64
82
|
elevation,
|
|
65
|
-
|
|
83
|
+
z,
|
|
84
|
+
altitude: z - elevation,
|
|
85
|
+
airborne: pose.airborne,
|
|
86
|
+
verticalSpeed: pose.vz,
|
|
87
|
+
hovering: pose.hovering,
|
|
88
|
+
hoverGauge: hoverGaugeOf(state),
|
|
89
|
+
},
|
|
90
|
+
});
|
|
66
91
|
}
|
|
67
|
-
if (
|
|
92
|
+
if (bodies.length === 0)
|
|
68
93
|
return null;
|
|
69
|
-
|
|
94
|
+
const key = (props) => (props.isSelf ? "self" : `remote-${props.id}`);
|
|
95
|
+
// Shadows first, so every body draws over every shadow.
|
|
96
|
+
const shadowSpots = shadowRenderer
|
|
97
|
+
? bodies.map(({ at, props }) => (_jsx(Spot, { shadow: true, x: at.x, y: at.y, lift: props.elevation * viewport.zoom + SHADOW_LIFT_PX, renderer: shadowRenderer, props: props }, `shadow-${key(props)}`)))
|
|
98
|
+
: [];
|
|
99
|
+
const bodySpots = bodies.map(({ at, props }) => (_jsx(Spot, { x: at.x, y: at.y, lift: props.z * viewport.zoom, renderer: renderer, props: props }, key(props))));
|
|
100
|
+
return (_jsxs("div", { style: {
|
|
70
101
|
position: "absolute",
|
|
71
102
|
inset: 0,
|
|
72
103
|
pointerEvents: "none",
|
|
73
104
|
transformStyle: "preserve-3d",
|
|
74
|
-
}, children:
|
|
105
|
+
}, children: [shadowSpots, bodySpots] }));
|
|
75
106
|
}
|
|
76
107
|
//# sourceMappingURL=character-layer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"character-layer.js","sourceRoot":"","sources":["../src/character-layer.tsx"],"names":[],"mappings":";AAAA,mFAAmF;AACnF,qFAAqF;AACrF,iFAAiF;AACjF,8EAA8E;AAC9E
|
|
1
|
+
{"version":3,"file":"character-layer.js","sourceRoot":"","sources":["../src/character-layer.tsx"],"names":[],"mappings":"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"}
|