@umicat/three-sdk 0.8.0 → 0.8.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/dist/Input3D.d.ts +16 -1
- package/dist/Input3D.js +57 -2
- package/dist/SceneLoader3D.js +36 -0
- package/package.json +1 -1
package/dist/Input3D.d.ts
CHANGED
|
@@ -52,7 +52,8 @@ export interface Input3DOptions {
|
|
|
52
52
|
* taps. Default on wherever touch controls are shown.
|
|
53
53
|
*/
|
|
54
54
|
look?: boolean;
|
|
55
|
-
/** Radians of camera rotation per screen-width dragged.
|
|
55
|
+
/** Radians of camera rotation per screen-width dragged. Same number governs
|
|
56
|
+
* touch drags and desktop right-drags, so there is one knob to turn. */
|
|
56
57
|
lookSensitivity?: number;
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
@@ -141,6 +142,20 @@ export declare class Input3D {
|
|
|
141
142
|
press(code: string): void;
|
|
142
143
|
release(code: string): void;
|
|
143
144
|
dispose(): void;
|
|
145
|
+
/**
|
|
146
|
+
* Desktop: hold the RIGHT mouse button and drag to turn the camera.
|
|
147
|
+
*
|
|
148
|
+
* The on-screen look zone only exists where the touch controls do, so
|
|
149
|
+
* without this a mouse-and-keyboard player has a camera they cannot turn at
|
|
150
|
+
* all — and now that movement is camera-relative, a camera you cannot turn
|
|
151
|
+
* is one that has permanently decided which way "forward" is.
|
|
152
|
+
*
|
|
153
|
+
* The right button rather than the left: a left-drag is how a game selects,
|
|
154
|
+
* clicks and aims, and taking that away from every game by default would be
|
|
155
|
+
* a worse trade than the one it fixes. Right-drag is also what Roblox uses
|
|
156
|
+
* on desktop, so it is already in players' hands.
|
|
157
|
+
*/
|
|
158
|
+
private mountMouseLook;
|
|
144
159
|
private mountTouch;
|
|
145
160
|
private wireButton;
|
|
146
161
|
}
|
package/dist/Input3D.js
CHANGED
|
@@ -69,7 +69,7 @@ export class Input3D {
|
|
|
69
69
|
this.actions = [];
|
|
70
70
|
this.stickMode = 'floating';
|
|
71
71
|
this.wantLook = true;
|
|
72
|
-
this.lookSens =
|
|
72
|
+
this.lookSens = 4.6;
|
|
73
73
|
this.lookDelta = { x: 0, y: 0 };
|
|
74
74
|
this.touchHeld = new Set();
|
|
75
75
|
this.pressedAt = new Map();
|
|
@@ -87,7 +87,10 @@ export class Input3D {
|
|
|
87
87
|
this.actions = opts.actions ?? [];
|
|
88
88
|
this.stickMode = opts.stick ?? 'floating';
|
|
89
89
|
this.wantLook = opts.look ?? true;
|
|
90
|
-
this.lookSens = opts.lookSensitivity ??
|
|
90
|
+
this.lookSens = opts.lookSensitivity ?? 4.6;
|
|
91
|
+
if (this.wantLook && typeof document !== 'undefined') {
|
|
92
|
+
this.mountMouseLook(opts.container?.ownerDocument ?? document);
|
|
93
|
+
}
|
|
91
94
|
const wantTouch = opts.touch === undefined || opts.touch === 'auto' ? isTouchDevice() : opts.touch;
|
|
92
95
|
if (wantTouch && typeof document !== 'undefined') {
|
|
93
96
|
this.mountTouch(opts.container ?? document.body);
|
|
@@ -194,6 +197,58 @@ export class Input3D {
|
|
|
194
197
|
this.root = null;
|
|
195
198
|
this.keysDown.clear();
|
|
196
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Desktop: hold the RIGHT mouse button and drag to turn the camera.
|
|
202
|
+
*
|
|
203
|
+
* The on-screen look zone only exists where the touch controls do, so
|
|
204
|
+
* without this a mouse-and-keyboard player has a camera they cannot turn at
|
|
205
|
+
* all — and now that movement is camera-relative, a camera you cannot turn
|
|
206
|
+
* is one that has permanently decided which way "forward" is.
|
|
207
|
+
*
|
|
208
|
+
* The right button rather than the left: a left-drag is how a game selects,
|
|
209
|
+
* clicks and aims, and taking that away from every game by default would be
|
|
210
|
+
* a worse trade than the one it fixes. Right-drag is also what Roblox uses
|
|
211
|
+
* on desktop, so it is already in players' hands.
|
|
212
|
+
*/
|
|
213
|
+
mountMouseLook(doc) {
|
|
214
|
+
let id = null;
|
|
215
|
+
let lastX = 0, lastY = 0;
|
|
216
|
+
const down = (e) => {
|
|
217
|
+
if (e.button !== 2 || e.pointerType === 'touch' || id !== null)
|
|
218
|
+
return;
|
|
219
|
+
id = e.pointerId;
|
|
220
|
+
lastX = e.clientX;
|
|
221
|
+
lastY = e.clientY;
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
};
|
|
224
|
+
const move = (e) => {
|
|
225
|
+
if (e.pointerId !== id)
|
|
226
|
+
return;
|
|
227
|
+
// Radians per screen WIDTH, the same unit the touch zone uses, so one
|
|
228
|
+
// sensitivity number means the same thing on both.
|
|
229
|
+
const w = Math.max(1, doc.defaultView?.innerWidth ?? 1000);
|
|
230
|
+
this.lookDelta.x += ((e.clientX - lastX) / w) * this.lookSens;
|
|
231
|
+
this.lookDelta.y += ((e.clientY - lastY) / w) * this.lookSens;
|
|
232
|
+
lastX = e.clientX;
|
|
233
|
+
lastY = e.clientY;
|
|
234
|
+
};
|
|
235
|
+
const up = (e) => { if (e.pointerId === id)
|
|
236
|
+
id = null; };
|
|
237
|
+
const menu = (e) => { e.preventDefault(); };
|
|
238
|
+
doc.addEventListener('pointerdown', down);
|
|
239
|
+
doc.addEventListener('pointermove', move);
|
|
240
|
+
doc.addEventListener('pointerup', up);
|
|
241
|
+
doc.addEventListener('pointercancel', up);
|
|
242
|
+
// Otherwise every right-drag ends with a context menu over the game.
|
|
243
|
+
doc.addEventListener('contextmenu', menu);
|
|
244
|
+
this.cleanups.push(() => {
|
|
245
|
+
doc.removeEventListener('pointerdown', down);
|
|
246
|
+
doc.removeEventListener('pointermove', move);
|
|
247
|
+
doc.removeEventListener('pointerup', up);
|
|
248
|
+
doc.removeEventListener('pointercancel', up);
|
|
249
|
+
doc.removeEventListener('contextmenu', menu);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
197
252
|
// ── on-screen controls ────────────────────────────────────────────────────
|
|
198
253
|
mountTouch(container) {
|
|
199
254
|
const root = document.createElement('div');
|
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.2",
|
|
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",
|