@umicat/three-sdk 0.8.1 → 0.8.3
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 +16 -0
- package/dist/Input3D.js +48 -3
- package/dist/SceneLoader3D.js +36 -0
- package/package.json +1 -1
package/dist/Input3D.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ export declare class Input3D {
|
|
|
84
84
|
private wantLook;
|
|
85
85
|
private lookSens;
|
|
86
86
|
private readonly lookDelta;
|
|
87
|
+
private enabled;
|
|
87
88
|
private readonly touchHeld;
|
|
88
89
|
private readonly pressedAt;
|
|
89
90
|
private readonly unconsumed;
|
|
@@ -91,6 +92,21 @@ export declare class Input3D {
|
|
|
91
92
|
private readonly cleanups;
|
|
92
93
|
constructor(options?: Input3DOptions | Window);
|
|
93
94
|
isDown(...codes: string[]): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Stop accepting input, and take the on-screen controls off the screen.
|
|
97
|
+
*
|
|
98
|
+
* For the moment a game puts a modal up — a game-over screen, a shop, a
|
|
99
|
+
* dialogue box. Two things go wrong otherwise, and the second is worse: the
|
|
100
|
+
* character keeps walking behind the dialog, and the controls' full-screen
|
|
101
|
+
* layer sits ABOVE the game's own DOM at z-index 10, so the button in that
|
|
102
|
+
* modal cannot be tapped at all. "Play Again" that does nothing is this bug.
|
|
103
|
+
*
|
|
104
|
+
* Disabling clears what was held, so a thumb that was pushing the stick when
|
|
105
|
+
* the modal opened does not resume walking when it closes.
|
|
106
|
+
*/
|
|
107
|
+
setEnabled(on: boolean): void;
|
|
108
|
+
/** Whether input is currently being accepted. */
|
|
109
|
+
get isEnabled(): boolean;
|
|
94
110
|
/**
|
|
95
111
|
* Which way to walk. Keyboard and stick are merged, so both work on a device
|
|
96
112
|
* with both.
|
package/dist/Input3D.js
CHANGED
|
@@ -71,6 +71,7 @@ export class Input3D {
|
|
|
71
71
|
this.wantLook = true;
|
|
72
72
|
this.lookSens = 4.6;
|
|
73
73
|
this.lookDelta = { x: 0, y: 0 };
|
|
74
|
+
this.enabled = true;
|
|
74
75
|
this.touchHeld = new Set();
|
|
75
76
|
this.pressedAt = new Map();
|
|
76
77
|
this.unconsumed = new Set();
|
|
@@ -96,7 +97,43 @@ export class Input3D {
|
|
|
96
97
|
this.mountTouch(opts.container ?? document.body);
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
|
-
isDown(...codes) {
|
|
100
|
+
isDown(...codes) {
|
|
101
|
+
return this.enabled && codes.some((c) => this.keysDown.has(c));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Stop accepting input, and take the on-screen controls off the screen.
|
|
105
|
+
*
|
|
106
|
+
* For the moment a game puts a modal up — a game-over screen, a shop, a
|
|
107
|
+
* dialogue box. Two things go wrong otherwise, and the second is worse: the
|
|
108
|
+
* character keeps walking behind the dialog, and the controls' full-screen
|
|
109
|
+
* layer sits ABOVE the game's own DOM at z-index 10, so the button in that
|
|
110
|
+
* modal cannot be tapped at all. "Play Again" that does nothing is this bug.
|
|
111
|
+
*
|
|
112
|
+
* Disabling clears what was held, so a thumb that was pushing the stick when
|
|
113
|
+
* the modal opened does not resume walking when it closes.
|
|
114
|
+
*/
|
|
115
|
+
setEnabled(on) {
|
|
116
|
+
this.enabled = on;
|
|
117
|
+
if (!on) {
|
|
118
|
+
this.keysDown.clear();
|
|
119
|
+
this.touchHeld.clear();
|
|
120
|
+
this.pressedAt.clear();
|
|
121
|
+
this.unconsumed.clear();
|
|
122
|
+
this.stick.x = 0;
|
|
123
|
+
this.stick.z = 0;
|
|
124
|
+
this.touchJump = false;
|
|
125
|
+
this.lookDelta.x = 0;
|
|
126
|
+
this.lookDelta.y = 0;
|
|
127
|
+
}
|
|
128
|
+
if (this.root) {
|
|
129
|
+
this.root.style.display = on ? '' : 'none';
|
|
130
|
+
// display:none alone would be enough for hit-testing, but a game that
|
|
131
|
+
// fades its modal in wants the controls gone, not just inert.
|
|
132
|
+
this.root.style.pointerEvents = 'none';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Whether input is currently being accepted. */
|
|
136
|
+
get isEnabled() { return this.enabled; }
|
|
100
137
|
/**
|
|
101
138
|
* Which way to walk. Keyboard and stick are merged, so both work on a device
|
|
102
139
|
* with both.
|
|
@@ -109,6 +146,8 @@ export class Input3D {
|
|
|
109
146
|
* behaviour, which is correct for a camera that never moves.
|
|
110
147
|
*/
|
|
111
148
|
direction(cameraYaw = 0) {
|
|
149
|
+
if (!this.enabled)
|
|
150
|
+
return { x: 0, z: 0 };
|
|
112
151
|
let x = this.stick.x, z = this.stick.z;
|
|
113
152
|
if (this.isDown('KeyW', 'ArrowUp'))
|
|
114
153
|
z -= 1;
|
|
@@ -131,9 +170,13 @@ export class Input3D {
|
|
|
131
170
|
}
|
|
132
171
|
/** Whether the jump control is held right now. Pass it to the controller —
|
|
133
172
|
* coyote time and buffering live there, not here. */
|
|
134
|
-
get jump() {
|
|
173
|
+
get jump() {
|
|
174
|
+
return this.enabled && this.held_('jump', this.touchJump || this.isDown('Space'));
|
|
175
|
+
}
|
|
135
176
|
/** Whether an action is held right now — button or bound key, same answer. */
|
|
136
177
|
held(id) {
|
|
178
|
+
if (!this.enabled)
|
|
179
|
+
return false;
|
|
137
180
|
const a = this.actions.find((x) => x.id === id);
|
|
138
181
|
return this.held_(id, this.touchHeld.has(id) || (a?.keys ? this.isDown(...a.keys) : false));
|
|
139
182
|
}
|
|
@@ -146,6 +189,8 @@ export class Input3D {
|
|
|
146
189
|
* it twice must not apply it twice. Pass straight to `LoadedScene3D.orbit`.
|
|
147
190
|
*/
|
|
148
191
|
look() {
|
|
192
|
+
if (!this.enabled)
|
|
193
|
+
return { x: 0, y: 0 };
|
|
149
194
|
const out = { x: this.lookDelta.x, y: this.lookDelta.y };
|
|
150
195
|
this.lookDelta.x = 0;
|
|
151
196
|
this.lookDelta.y = 0;
|
|
@@ -157,7 +202,7 @@ export class Input3D {
|
|
|
157
202
|
* to last frame's, which means a press that begins and ends between two
|
|
158
203
|
* frames never happened. This latches at the event, so it cannot be missed
|
|
159
204
|
* — and it clears on read, so holding the button does not chain. */
|
|
160
|
-
consume(id) { return this.unconsumed.delete(id); }
|
|
205
|
+
consume(id) { return this.enabled && this.unconsumed.delete(id); }
|
|
161
206
|
held_(id, physical) {
|
|
162
207
|
if (physical)
|
|
163
208
|
return true;
|
package/dist/SceneLoader3D.js
CHANGED
|
@@ -211,6 +211,42 @@ export async function loadScene3D(scene3d, manifest, opts = {}) {
|
|
|
211
211
|
bodies.set(e.id, body);
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
|
+
// Fit every shadow-casting directional light to the scene it is lighting.
|
|
215
|
+
//
|
|
216
|
+
// three.js defaults a directional light's shadow camera to an orthographic
|
|
217
|
+
// box of +-5 units, and nothing warns when a scene is larger: shadows simply
|
|
218
|
+
// stop at an invisible square edge, which reads as a strange dark patch in
|
|
219
|
+
// the middle of the ground rather than as a setting. A board 13 units across
|
|
220
|
+
// hits it immediately.
|
|
221
|
+
{
|
|
222
|
+
const bounds = new THREE.Box3();
|
|
223
|
+
for (const o of entities.values())
|
|
224
|
+
bounds.expandByObject(o);
|
|
225
|
+
if (!bounds.isEmpty()) {
|
|
226
|
+
const size = bounds.getSize(new THREE.Vector3());
|
|
227
|
+
const centre = bounds.getCenter(new THREE.Vector3());
|
|
228
|
+
const radius = Math.max(size.x, size.z) * 0.62 + 1;
|
|
229
|
+
for (const l of scene.children) {
|
|
230
|
+
const d = l;
|
|
231
|
+
if (!d.isDirectionalLight || !d.castShadow)
|
|
232
|
+
continue;
|
|
233
|
+
const c = d.shadow.camera;
|
|
234
|
+
c.left = -radius;
|
|
235
|
+
c.right = radius;
|
|
236
|
+
c.top = radius;
|
|
237
|
+
c.bottom = -radius;
|
|
238
|
+
c.near = 0.1;
|
|
239
|
+
c.far = d.position.length() + radius * 2 + size.y;
|
|
240
|
+
c.updateProjectionMatrix();
|
|
241
|
+
// The light points at the scene, not at the origin — an offset scene
|
|
242
|
+
// would otherwise be lit from the side of a box centred somewhere else.
|
|
243
|
+
d.target.position.copy(centre);
|
|
244
|
+
scene.add(d.target);
|
|
245
|
+
d.shadow.mapSize.set(2048, 2048);
|
|
246
|
+
d.shadow.bias = -0.0012;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
214
250
|
const camera = new THREE.PerspectiveCamera(scene3d.camera?.fov ?? 55, 1, 0.1, 500);
|
|
215
251
|
const camOffset = toVec(scene3d.camera?.offset ?? { x: 0, y: 4, z: 8 });
|
|
216
252
|
camera.position.copy(camOffset);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umicat/three-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
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",
|