@umicat/three-sdk 0.8.2 → 0.8.4
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/dist/Input3D.d.ts +28 -0
- package/dist/Input3D.js +52 -5
- package/package.json +1 -1
package/dist/Input3D.d.ts
CHANGED
|
@@ -55,6 +55,17 @@ export interface Input3DOptions {
|
|
|
55
55
|
/** Radians of camera rotation per screen-width dragged. Same number governs
|
|
56
56
|
* touch drags and desktop right-drags, so there is one knob to turn. */
|
|
57
57
|
lookSensitivity?: number;
|
|
58
|
+
/**
|
|
59
|
+
* How much of the top of the screen the move and look zones leave alone.
|
|
60
|
+
*
|
|
61
|
+
* A HUD lives at the top — score, hearts, a mute button — and the zones are
|
|
62
|
+
* full-screen and sit ABOVE the game's DOM, so without this every button up
|
|
63
|
+
* there is unreachable on a phone while looking perfectly fine. Nobody
|
|
64
|
+
* drives a thumbstick from the top edge, so the trade is free.
|
|
65
|
+
*
|
|
66
|
+
* A CSS length; the default is `max(64px, 12%)`.
|
|
67
|
+
*/
|
|
68
|
+
controlsTopInset?: string;
|
|
58
69
|
}
|
|
59
70
|
/**
|
|
60
71
|
* Movement and jump, from a keyboard or a thumb, behind one interface.
|
|
@@ -82,8 +93,10 @@ export declare class Input3D {
|
|
|
82
93
|
private actions;
|
|
83
94
|
private stickMode;
|
|
84
95
|
private wantLook;
|
|
96
|
+
private topInset;
|
|
85
97
|
private lookSens;
|
|
86
98
|
private readonly lookDelta;
|
|
99
|
+
private enabled;
|
|
87
100
|
private readonly touchHeld;
|
|
88
101
|
private readonly pressedAt;
|
|
89
102
|
private readonly unconsumed;
|
|
@@ -91,6 +104,21 @@ export declare class Input3D {
|
|
|
91
104
|
private readonly cleanups;
|
|
92
105
|
constructor(options?: Input3DOptions | Window);
|
|
93
106
|
isDown(...codes: string[]): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Stop accepting input, and take the on-screen controls off the screen.
|
|
109
|
+
*
|
|
110
|
+
* For the moment a game puts a modal up — a game-over screen, a shop, a
|
|
111
|
+
* dialogue box. Two things go wrong otherwise, and the second is worse: the
|
|
112
|
+
* character keeps walking behind the dialog, and the controls' full-screen
|
|
113
|
+
* layer sits ABOVE the game's own DOM at z-index 10, so the button in that
|
|
114
|
+
* modal cannot be tapped at all. "Play Again" that does nothing is this bug.
|
|
115
|
+
*
|
|
116
|
+
* Disabling clears what was held, so a thumb that was pushing the stick when
|
|
117
|
+
* the modal opened does not resume walking when it closes.
|
|
118
|
+
*/
|
|
119
|
+
setEnabled(on: boolean): void;
|
|
120
|
+
/** Whether input is currently being accepted. */
|
|
121
|
+
get isEnabled(): boolean;
|
|
94
122
|
/**
|
|
95
123
|
* Which way to walk. Keyboard and stick are merged, so both work on a device
|
|
96
124
|
* with both.
|
package/dist/Input3D.js
CHANGED
|
@@ -69,8 +69,10 @@ export class Input3D {
|
|
|
69
69
|
this.actions = [];
|
|
70
70
|
this.stickMode = 'floating';
|
|
71
71
|
this.wantLook = true;
|
|
72
|
+
this.topInset = 'max(64px, 12%)';
|
|
72
73
|
this.lookSens = 4.6;
|
|
73
74
|
this.lookDelta = { x: 0, y: 0 };
|
|
75
|
+
this.enabled = true;
|
|
74
76
|
this.touchHeld = new Set();
|
|
75
77
|
this.pressedAt = new Map();
|
|
76
78
|
this.unconsumed = new Set();
|
|
@@ -87,6 +89,7 @@ export class Input3D {
|
|
|
87
89
|
this.actions = opts.actions ?? [];
|
|
88
90
|
this.stickMode = opts.stick ?? 'floating';
|
|
89
91
|
this.wantLook = opts.look ?? true;
|
|
92
|
+
this.topInset = opts.controlsTopInset ?? 'max(64px, 12%)';
|
|
90
93
|
this.lookSens = opts.lookSensitivity ?? 4.6;
|
|
91
94
|
if (this.wantLook && typeof document !== 'undefined') {
|
|
92
95
|
this.mountMouseLook(opts.container?.ownerDocument ?? document);
|
|
@@ -96,7 +99,43 @@ export class Input3D {
|
|
|
96
99
|
this.mountTouch(opts.container ?? document.body);
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
|
-
isDown(...codes) {
|
|
102
|
+
isDown(...codes) {
|
|
103
|
+
return this.enabled && codes.some((c) => this.keysDown.has(c));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Stop accepting input, and take the on-screen controls off the screen.
|
|
107
|
+
*
|
|
108
|
+
* For the moment a game puts a modal up — a game-over screen, a shop, a
|
|
109
|
+
* dialogue box. Two things go wrong otherwise, and the second is worse: the
|
|
110
|
+
* character keeps walking behind the dialog, and the controls' full-screen
|
|
111
|
+
* layer sits ABOVE the game's own DOM at z-index 10, so the button in that
|
|
112
|
+
* modal cannot be tapped at all. "Play Again" that does nothing is this bug.
|
|
113
|
+
*
|
|
114
|
+
* Disabling clears what was held, so a thumb that was pushing the stick when
|
|
115
|
+
* the modal opened does not resume walking when it closes.
|
|
116
|
+
*/
|
|
117
|
+
setEnabled(on) {
|
|
118
|
+
this.enabled = on;
|
|
119
|
+
if (!on) {
|
|
120
|
+
this.keysDown.clear();
|
|
121
|
+
this.touchHeld.clear();
|
|
122
|
+
this.pressedAt.clear();
|
|
123
|
+
this.unconsumed.clear();
|
|
124
|
+
this.stick.x = 0;
|
|
125
|
+
this.stick.z = 0;
|
|
126
|
+
this.touchJump = false;
|
|
127
|
+
this.lookDelta.x = 0;
|
|
128
|
+
this.lookDelta.y = 0;
|
|
129
|
+
}
|
|
130
|
+
if (this.root) {
|
|
131
|
+
this.root.style.display = on ? '' : 'none';
|
|
132
|
+
// display:none alone would be enough for hit-testing, but a game that
|
|
133
|
+
// fades its modal in wants the controls gone, not just inert.
|
|
134
|
+
this.root.style.pointerEvents = 'none';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Whether input is currently being accepted. */
|
|
138
|
+
get isEnabled() { return this.enabled; }
|
|
100
139
|
/**
|
|
101
140
|
* Which way to walk. Keyboard and stick are merged, so both work on a device
|
|
102
141
|
* with both.
|
|
@@ -109,6 +148,8 @@ export class Input3D {
|
|
|
109
148
|
* behaviour, which is correct for a camera that never moves.
|
|
110
149
|
*/
|
|
111
150
|
direction(cameraYaw = 0) {
|
|
151
|
+
if (!this.enabled)
|
|
152
|
+
return { x: 0, z: 0 };
|
|
112
153
|
let x = this.stick.x, z = this.stick.z;
|
|
113
154
|
if (this.isDown('KeyW', 'ArrowUp'))
|
|
114
155
|
z -= 1;
|
|
@@ -131,9 +172,13 @@ export class Input3D {
|
|
|
131
172
|
}
|
|
132
173
|
/** Whether the jump control is held right now. Pass it to the controller —
|
|
133
174
|
* coyote time and buffering live there, not here. */
|
|
134
|
-
get jump() {
|
|
175
|
+
get jump() {
|
|
176
|
+
return this.enabled && this.held_('jump', this.touchJump || this.isDown('Space'));
|
|
177
|
+
}
|
|
135
178
|
/** Whether an action is held right now — button or bound key, same answer. */
|
|
136
179
|
held(id) {
|
|
180
|
+
if (!this.enabled)
|
|
181
|
+
return false;
|
|
137
182
|
const a = this.actions.find((x) => x.id === id);
|
|
138
183
|
return this.held_(id, this.touchHeld.has(id) || (a?.keys ? this.isDown(...a.keys) : false));
|
|
139
184
|
}
|
|
@@ -146,6 +191,8 @@ export class Input3D {
|
|
|
146
191
|
* it twice must not apply it twice. Pass straight to `LoadedScene3D.orbit`.
|
|
147
192
|
*/
|
|
148
193
|
look() {
|
|
194
|
+
if (!this.enabled)
|
|
195
|
+
return { x: 0, y: 0 };
|
|
149
196
|
const out = { x: this.lookDelta.x, y: this.lookDelta.y };
|
|
150
197
|
this.lookDelta.x = 0;
|
|
151
198
|
this.lookDelta.y = 0;
|
|
@@ -157,7 +204,7 @@ export class Input3D {
|
|
|
157
204
|
* to last frame's, which means a press that begins and ends between two
|
|
158
205
|
* frames never happened. This latches at the event, so it cannot be missed
|
|
159
206
|
* — and it clears on read, so holding the button does not chain. */
|
|
160
|
-
consume(id) { return this.unconsumed.delete(id); }
|
|
207
|
+
consume(id) { return this.enabled && this.unconsumed.delete(id); }
|
|
161
208
|
held_(id, physical) {
|
|
162
209
|
if (physical)
|
|
163
210
|
return true;
|
|
@@ -269,7 +316,7 @@ export class Input3D {
|
|
|
269
316
|
// anything. It deliberately stops short of the buttons on the right.
|
|
270
317
|
const zone = document.createElement('div');
|
|
271
318
|
Object.assign(zone.style, {
|
|
272
|
-
position: 'absolute', left: '0', top:
|
|
319
|
+
position: 'absolute', left: '0', top: this.topInset, width: '50%', bottom: '0',
|
|
273
320
|
pointerEvents: floating ? 'auto' : 'none',
|
|
274
321
|
});
|
|
275
322
|
Object.assign(zone.style, NO_SELECTION);
|
|
@@ -278,7 +325,7 @@ export class Input3D {
|
|
|
278
325
|
// can be the whole right half rather than an awkward cut-out around them.
|
|
279
326
|
const lookZone = document.createElement('div');
|
|
280
327
|
Object.assign(lookZone.style, {
|
|
281
|
-
position: 'absolute', right: '0', top:
|
|
328
|
+
position: 'absolute', right: '0', top: this.topInset, width: '50%', bottom: '0',
|
|
282
329
|
pointerEvents: this.wantLook ? 'auto' : 'none',
|
|
283
330
|
});
|
|
284
331
|
Object.assign(lookZone.style, NO_SELECTION);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umicat/three-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Three.js runtime for Umicat games: the scene3d design format, its loader with physics, a kinematic character controller, and the Umicat platform via @umicat/platform-sdk.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|