easter-egg-quest 1.0.7 → 1.0.9
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.
|
@@ -1365,8 +1365,39 @@ class ThreeRenderer {
|
|
|
1365
1365
|
this._collectFlashOpacity = 0;
|
|
1366
1366
|
this._collectShake = 0;
|
|
1367
1367
|
this._collectCamBaseZ = 5;
|
|
1368
|
+
this._finaleInteractive = false;
|
|
1369
|
+
this._finaleDragTarget = null;
|
|
1370
|
+
this._finalePausedRotation = [false, false, false];
|
|
1368
1371
|
this._onPointerDown = (e) => {
|
|
1369
|
-
if (this.
|
|
1372
|
+
if (this._disposed) return;
|
|
1373
|
+
if (this._finaleInteractive && this._finaleActive) {
|
|
1374
|
+
let bestIdx = -1;
|
|
1375
|
+
let bestDist = Infinity;
|
|
1376
|
+
for (let i = 0; i < 3; i++) {
|
|
1377
|
+
const egg3 = this.eggs[i];
|
|
1378
|
+
if (!egg3 || !egg3.visible) continue;
|
|
1379
|
+
const scr = this._worldToScreen(egg3.position);
|
|
1380
|
+
const d = Math.sqrt((e.clientX - scr.x) ** 2 + (e.clientY - scr.y) ** 2);
|
|
1381
|
+
if (d < bestDist) {
|
|
1382
|
+
bestDist = d;
|
|
1383
|
+
bestIdx = i;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
if (bestIdx < 0 || bestDist > 140) return;
|
|
1387
|
+
e.preventDefault();
|
|
1388
|
+
e.stopPropagation();
|
|
1389
|
+
this._finaleDragTarget = bestIdx;
|
|
1390
|
+
this._isDragging = true;
|
|
1391
|
+
this._dragMoved = false;
|
|
1392
|
+
this._dragStartX = e.clientX;
|
|
1393
|
+
this._dragStartY = e.clientY;
|
|
1394
|
+
const egg2 = this.eggs[bestIdx];
|
|
1395
|
+
this._dragRotX = egg2.rotation.x;
|
|
1396
|
+
this._dragRotY = egg2.rotation.y;
|
|
1397
|
+
document.body.style.cursor = "grabbing";
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (this._interactiveEgg === null) return;
|
|
1370
1401
|
const egg = this.eggs[this._interactiveEgg];
|
|
1371
1402
|
if (!egg || !egg.visible) return;
|
|
1372
1403
|
const eggScreen = this._worldToScreen(egg.position);
|
|
@@ -1388,7 +1419,22 @@ class ThreeRenderer {
|
|
|
1388
1419
|
this._holdProgress = 0;
|
|
1389
1420
|
};
|
|
1390
1421
|
this._onPointerMove = (e) => {
|
|
1391
|
-
if (!this._isDragging
|
|
1422
|
+
if (!this._isDragging) return;
|
|
1423
|
+
if (this._finaleDragTarget !== null) {
|
|
1424
|
+
e.preventDefault();
|
|
1425
|
+
e.stopPropagation();
|
|
1426
|
+
const egg2 = this.eggs[this._finaleDragTarget];
|
|
1427
|
+
if (!egg2) return;
|
|
1428
|
+
const dx2 = e.clientX - this._dragStartX;
|
|
1429
|
+
const dy2 = e.clientY - this._dragStartY;
|
|
1430
|
+
egg2.rotation.y = this._dragRotY + dx2 * 8e-3;
|
|
1431
|
+
egg2.rotation.x = this._dragRotX + dy2 * 5e-3;
|
|
1432
|
+
if (Math.abs(dx2) > 5 || Math.abs(dy2) > 5) {
|
|
1433
|
+
this._finalePausedRotation[this._finaleDragTarget] = true;
|
|
1434
|
+
}
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
if (this._interactiveEgg === null) return;
|
|
1392
1438
|
e.preventDefault();
|
|
1393
1439
|
e.stopPropagation();
|
|
1394
1440
|
const egg = this.eggs[this._interactiveEgg];
|
|
@@ -1408,43 +1454,29 @@ class ThreeRenderer {
|
|
|
1408
1454
|
e.stopPropagation();
|
|
1409
1455
|
}
|
|
1410
1456
|
this._isDragging = false;
|
|
1457
|
+
this._finaleDragTarget = null;
|
|
1411
1458
|
this._cancelLongPress();
|
|
1412
|
-
if (this._interactiveEgg !== null) {
|
|
1459
|
+
if (this._interactiveEgg !== null || this._finaleInteractive) {
|
|
1413
1460
|
document.body.style.cursor = "grab";
|
|
1414
1461
|
}
|
|
1415
1462
|
};
|
|
1416
1463
|
this._onWheel = (e) => {
|
|
1417
|
-
if (this.
|
|
1418
|
-
|
|
1419
|
-
if (!egg || !egg.visible) return;
|
|
1420
|
-
const eggScreen = this._worldToScreen(egg.position);
|
|
1421
|
-
const dx = e.clientX - eggScreen.x;
|
|
1422
|
-
const dy = e.clientY - eggScreen.y;
|
|
1423
|
-
if (Math.sqrt(dx * dx + dy * dy) <= 120) {
|
|
1464
|
+
if (this._disposed) return;
|
|
1465
|
+
if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
|
|
1424
1466
|
e.preventDefault();
|
|
1425
1467
|
e.stopPropagation();
|
|
1426
1468
|
}
|
|
1427
1469
|
};
|
|
1428
1470
|
this._onClickCapture = (e) => {
|
|
1429
|
-
if (this.
|
|
1430
|
-
|
|
1431
|
-
if (!egg || !egg.visible) return;
|
|
1432
|
-
const eggScreen = this._worldToScreen(egg.position);
|
|
1433
|
-
const dx = e.clientX - eggScreen.x;
|
|
1434
|
-
const dy = e.clientY - eggScreen.y;
|
|
1435
|
-
if (Math.sqrt(dx * dx + dy * dy) <= 120) {
|
|
1471
|
+
if (this._disposed) return;
|
|
1472
|
+
if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
|
|
1436
1473
|
e.preventDefault();
|
|
1437
1474
|
e.stopPropagation();
|
|
1438
1475
|
}
|
|
1439
1476
|
};
|
|
1440
1477
|
this._onMouseDownCapture = (e) => {
|
|
1441
|
-
if (this.
|
|
1442
|
-
|
|
1443
|
-
if (!egg || !egg.visible) return;
|
|
1444
|
-
const eggScreen = this._worldToScreen(egg.position);
|
|
1445
|
-
const dx = e.clientX - eggScreen.x;
|
|
1446
|
-
const dy = e.clientY - eggScreen.y;
|
|
1447
|
-
if (Math.sqrt(dx * dx + dy * dy) <= 120) {
|
|
1478
|
+
if (this._disposed) return;
|
|
1479
|
+
if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
|
|
1448
1480
|
e.preventDefault();
|
|
1449
1481
|
e.stopPropagation();
|
|
1450
1482
|
}
|
|
@@ -1456,15 +1488,10 @@ class ThreeRenderer {
|
|
|
1456
1488
|
}
|
|
1457
1489
|
};
|
|
1458
1490
|
this._onTouchStartCapture = (e) => {
|
|
1459
|
-
if (this.
|
|
1460
|
-
const egg = this.eggs[this._interactiveEgg];
|
|
1461
|
-
if (!egg || !egg.visible) return;
|
|
1491
|
+
if (this._disposed) return;
|
|
1462
1492
|
const touch = e.touches[0];
|
|
1463
1493
|
if (!touch) return;
|
|
1464
|
-
|
|
1465
|
-
const dx = touch.clientX - eggScreen.x;
|
|
1466
|
-
const dy = touch.clientY - eggScreen.y;
|
|
1467
|
-
if (Math.sqrt(dx * dx + dy * dy) <= 120) {
|
|
1494
|
+
if (this._isPointerNearAnyEgg(touch.clientX, touch.clientY)) {
|
|
1468
1495
|
e.preventDefault();
|
|
1469
1496
|
e.stopPropagation();
|
|
1470
1497
|
}
|
|
@@ -1578,6 +1605,8 @@ class ThreeRenderer {
|
|
|
1578
1605
|
disableInteraction() {
|
|
1579
1606
|
this._interactiveEgg = null;
|
|
1580
1607
|
this._isDragging = false;
|
|
1608
|
+
this._finaleDragTarget = null;
|
|
1609
|
+
this._finaleInteractive = false;
|
|
1581
1610
|
this._cancelLongPress();
|
|
1582
1611
|
document.body.style.cursor = "";
|
|
1583
1612
|
}
|
|
@@ -1720,6 +1749,10 @@ class ThreeRenderer {
|
|
|
1720
1749
|
this._finaleActive = true;
|
|
1721
1750
|
this._finaleT = 0;
|
|
1722
1751
|
this.disableInteraction();
|
|
1752
|
+
this._finaleInteractive = true;
|
|
1753
|
+
this._finaleDragTarget = null;
|
|
1754
|
+
this._finalePausedRotation = [false, false, false];
|
|
1755
|
+
document.body.style.cursor = "grab";
|
|
1723
1756
|
for (let i = 0; i < 3; i++) {
|
|
1724
1757
|
const state = this._eggStates[i];
|
|
1725
1758
|
state.phase = "finale";
|
|
@@ -2594,6 +2627,25 @@ class ThreeRenderer {
|
|
|
2594
2627
|
y: (-v.y * 0.5 + 0.5) * window.innerHeight
|
|
2595
2628
|
};
|
|
2596
2629
|
}
|
|
2630
|
+
/** Check if pointer is near any active egg (interactive or finale). */
|
|
2631
|
+
_isPointerNearAnyEgg(px, py) {
|
|
2632
|
+
if (this._finaleInteractive) {
|
|
2633
|
+
for (let i = 0; i < 3; i++) {
|
|
2634
|
+
const egg2 = this.eggs[i];
|
|
2635
|
+
if (!egg2 || !egg2.visible) continue;
|
|
2636
|
+
const scr2 = this._worldToScreen(egg2.position);
|
|
2637
|
+
const d2 = Math.sqrt((px - scr2.x) ** 2 + (py - scr2.y) ** 2);
|
|
2638
|
+
if (d2 <= 140) return true;
|
|
2639
|
+
}
|
|
2640
|
+
return false;
|
|
2641
|
+
}
|
|
2642
|
+
if (this._interactiveEgg === null) return false;
|
|
2643
|
+
const egg = this.eggs[this._interactiveEgg];
|
|
2644
|
+
if (!egg || !egg.visible) return false;
|
|
2645
|
+
const scr = this._worldToScreen(egg.position);
|
|
2646
|
+
const d = Math.sqrt((px - scr.x) ** 2 + (py - scr.y) ** 2);
|
|
2647
|
+
return d <= 120;
|
|
2648
|
+
}
|
|
2597
2649
|
_screenToWorld(sx, sy) {
|
|
2598
2650
|
const T = this.THREE;
|
|
2599
2651
|
const ndcX = sx / window.innerWidth * 2 - 1;
|
|
@@ -2780,7 +2832,9 @@ class ThreeRenderer {
|
|
|
2780
2832
|
group.position.x += (tx - group.position.x) * 0.06;
|
|
2781
2833
|
group.position.y += (ty - group.position.y) * 0.06;
|
|
2782
2834
|
group.position.z += (tz - group.position.z) * 0.06;
|
|
2783
|
-
|
|
2835
|
+
if (!this._finalePausedRotation[i]) {
|
|
2836
|
+
group.rotation.y = this._finaleT * 0.4 + i * (Math.PI * 2 / 3);
|
|
2837
|
+
}
|
|
2784
2838
|
group.scale.setScalar(
|
|
2785
2839
|
group.scale.x + (eggScale - group.scale.x) * 0.04
|
|
2786
2840
|
);
|
|
@@ -4141,6 +4195,8 @@ class MotionStage {
|
|
|
4141
4195
|
}
|
|
4142
4196
|
this.bus.emit("narrative:clear");
|
|
4143
4197
|
await this._wait(1e3);
|
|
4198
|
+
this._lastUpdateTime = Date.now();
|
|
4199
|
+
this._movingAccum = 0;
|
|
4144
4200
|
this._introPlayed = true;
|
|
4145
4201
|
}
|
|
4146
4202
|
update(_dt) {
|
|
@@ -4254,8 +4310,9 @@ class RhythmStage {
|
|
|
4254
4310
|
}
|
|
4255
4311
|
this.bus.emit("narrative:clear");
|
|
4256
4312
|
await this._wait(1e3);
|
|
4257
|
-
this.
|
|
4313
|
+
this.input.resetPhases();
|
|
4258
4314
|
this._lastPhaseCount = this.input.phases.length;
|
|
4315
|
+
this._introPlayed = true;
|
|
4259
4316
|
}
|
|
4260
4317
|
update(_dt) {
|
|
4261
4318
|
if (this._status === "complete" || !this._introPlayed) return this._status;
|
|
@@ -4963,7 +5020,8 @@ class GameController {
|
|
|
4963
5020
|
}
|
|
4964
5021
|
// ─── Stage Progress ────────────────────────────────────────────────────
|
|
4965
5022
|
_handleStageProgress(progress) {
|
|
4966
|
-
|
|
5023
|
+
const stage = this.fsm.state;
|
|
5024
|
+
if (this.threeRenderer && stage !== "stage3-active") {
|
|
4967
5025
|
this.threeRenderer.showProgressParticles(progress);
|
|
4968
5026
|
}
|
|
4969
5027
|
const now = Date.now();
|