@umicat/three-sdk 0.13.0 → 0.15.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/dist/GameAudio.js +13 -0
- package/dist/Input3D.js +53 -4
- package/package.json +1 -1
package/dist/GameAudio.js
CHANGED
|
@@ -230,6 +230,19 @@ export class GameAudio {
|
|
|
230
230
|
const ctx = this.ctx;
|
|
231
231
|
if (this.muted)
|
|
232
232
|
return;
|
|
233
|
+
// The music may still be waiting for a gesture even though the context is
|
|
234
|
+
// not. `start()` is the only other place that starts it, and it early-exits
|
|
235
|
+
// when the context is ALREADY running — which is what happens in a
|
|
236
|
+
// cross-origin iframe, where the context comes up running and the first
|
|
237
|
+
// `play()` therefore never takes the unlock path. Measured: a game
|
|
238
|
+
// embedded that way had a live context, decoded buffers, working effects
|
|
239
|
+
// and no music at all, because `startMusic()` had never been reached.
|
|
240
|
+
//
|
|
241
|
+
// `play()` is the right place for the second attempt: it is called from
|
|
242
|
+
// inside a real gesture (a button, a move), which is exactly the
|
|
243
|
+
// permission an element needs, and `startMusic` is idempotent.
|
|
244
|
+
if (this.ready && this.musicName && !this.musicEl)
|
|
245
|
+
this.startMusic();
|
|
233
246
|
if (!this.ready || !ctx || !this.master) {
|
|
234
247
|
// Not "drop it": this is the unlocking gesture, and the sound it asked
|
|
235
248
|
// for is the one the player is waiting to hear. `start()` plays it.
|
package/dist/Input3D.js
CHANGED
|
@@ -409,10 +409,9 @@ export class Input3D {
|
|
|
409
409
|
transform: 'translate(-50%, -50%)', pointerEvents: 'none',
|
|
410
410
|
});
|
|
411
411
|
pad.appendChild(knob);
|
|
412
|
-
// ONE cluster holds every button,
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
// was; actions stack to its left and wrap upward.
|
|
412
|
+
// ONE cluster holds every button, because the bug this replaces was two of
|
|
413
|
+
// them independently choosing "bottom right" and landing on top of each
|
|
414
|
+
// other. What it does with them is `layOnArc` below.
|
|
416
415
|
const cluster = document.createElement('div');
|
|
417
416
|
Object.assign(cluster.style, {
|
|
418
417
|
position: 'absolute', right: '6vmin', bottom: '7vmin',
|
|
@@ -420,6 +419,53 @@ export class Input3D {
|
|
|
420
419
|
flexWrap: 'wrap-reverse', justifyContent: 'flex-start',
|
|
421
420
|
gap: '3vmin', maxWidth: '52vmin', pointerEvents: 'none',
|
|
422
421
|
});
|
|
422
|
+
/**
|
|
423
|
+
* Put the buttons on the arc a THUMB actually sweeps.
|
|
424
|
+
*
|
|
425
|
+
* They were a wrapping flex row, which is how they ended up in a straight
|
|
426
|
+
* line across the bottom of the screen the moment a game had exactly two —
|
|
427
|
+
* the third button had been the only thing forcing a wrap, so removing it
|
|
428
|
+
* silently changed the layout of the two that were left. A row is also the
|
|
429
|
+
* wrong shape regardless: a thumb is hinged at the bottom corner and moves
|
|
430
|
+
* on an arc around it, so buttons at the same HEIGHT are at different
|
|
431
|
+
* reaches, and the far one is the one that gets missed.
|
|
432
|
+
*
|
|
433
|
+
* So: a quarter circle centred on the corner. Index 0 sits low and to the
|
|
434
|
+
* left, and each one after it steps up and in toward the edge, every one of
|
|
435
|
+
* them the same distance from the thumb's hinge.
|
|
436
|
+
*
|
|
437
|
+
* The radius is DERIVED, not chosen: neighbours must be at least a button
|
|
438
|
+
* apart along the chord, so a wider sweep — which is what more buttons
|
|
439
|
+
* need — pushes the arc out. Past three the radius it asks for has the
|
|
440
|
+
* buttons halfway up the screen, so the old wrapping row is kept for that
|
|
441
|
+
* case rather than pretending an arc still fits.
|
|
442
|
+
*/
|
|
443
|
+
const layOnArc = (els) => {
|
|
444
|
+
const S = 20; // vmin — the button size, below
|
|
445
|
+
const [A0, A1] = [16, 74]; // degrees, the comfortable sweep
|
|
446
|
+
if (els.length > 3)
|
|
447
|
+
return; // the flex row stays as it is
|
|
448
|
+
const step = els.length > 1 ? (A1 - A0) / (els.length - 1) : 0;
|
|
449
|
+
// Chord between neighbours = 2R·sin(step/2), and it may not be smaller
|
|
450
|
+
// than a button plus a little air.
|
|
451
|
+
const need = els.length > 1 ? (S * 1.12) / (2 * Math.sin((step * Math.PI) / 360)) : S * 1.3;
|
|
452
|
+
const R = Math.max(S * 1.3, need);
|
|
453
|
+
cluster.style.display = 'block';
|
|
454
|
+
cluster.style.width = '0';
|
|
455
|
+
cluster.style.height = '0';
|
|
456
|
+
els.forEach((el, i) => {
|
|
457
|
+
const t = ((A0 + step * i) * Math.PI) / 180;
|
|
458
|
+
// From the corner, in vmin, then back off by half a button so the
|
|
459
|
+
// ARC passes through each button's middle rather than its corner.
|
|
460
|
+
const dx = (R * Math.cos(t)).toFixed(2);
|
|
461
|
+
const dy = (R * Math.sin(t)).toFixed(2);
|
|
462
|
+
Object.assign(el.style, {
|
|
463
|
+
position: 'absolute',
|
|
464
|
+
right: `calc(${dx}vmin - min(${S / 2}vmin, 60px))`,
|
|
465
|
+
bottom: `calc(${dy}vmin - min(${S / 2}vmin, 60px))`,
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
};
|
|
423
469
|
/** Returns the button; its glyph, if it has one, is left in `glyph`. */
|
|
424
470
|
let glyph = null;
|
|
425
471
|
const makeButton = (label, icon) => {
|
|
@@ -480,11 +526,13 @@ export class Input3D {
|
|
|
480
526
|
...this.actions.map((a) => ({ id: a.id, label: a.label ?? a.id.slice(0, 1).toUpperCase(), icon: a.icon })),
|
|
481
527
|
];
|
|
482
528
|
let jumpBtn = null;
|
|
529
|
+
const made = [];
|
|
483
530
|
for (const b of buttons) {
|
|
484
531
|
const el = makeButton(b.label, b.icon);
|
|
485
532
|
if (glyph)
|
|
486
533
|
this.glyphs.set(b.id, glyph);
|
|
487
534
|
cluster.append(el);
|
|
535
|
+
made.push(el);
|
|
488
536
|
// Jump is the platform's own: its press is read through `get jump()`
|
|
489
537
|
// rather than through the action latch, so it is wired below instead.
|
|
490
538
|
if (b.id === 'jump')
|
|
@@ -492,6 +540,7 @@ export class Input3D {
|
|
|
492
540
|
else
|
|
493
541
|
this.wireButton(el, b.id);
|
|
494
542
|
}
|
|
543
|
+
layOnArc(made);
|
|
495
544
|
root.append(zone, lookZone, pad, cluster);
|
|
496
545
|
container.appendChild(root);
|
|
497
546
|
this.root = root;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umicat/three-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
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",
|