RayMelius Claude Opus 4.6 commited on
Commit
a23c245
Β·
1 Parent(s): cc5e6c5

Fix FPV NPC chat: overlay no longer blocks dialog, add interact prompt

Browse files
Files changed (1) hide show
  1. web/3d.html +36 -1
web/3d.html CHANGED
@@ -272,6 +272,9 @@
272
  <div id="fp-hint" style="display:none;position:fixed;bottom:60px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.7);color:#fff;padding:8px 16px;border-radius:8px;font-size:13px;z-index:50;text-align:center">
273
  WASD β€” move &middot; Mouse β€” look &middot; E β€” talk to NPC &middot; ESC β€” exit
274
  </div>
 
 
 
275
  <div id="fp-click-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:250;cursor:pointer;display:none;align-items:center;justify-content:center">
276
  <div style="text-align:center;color:#fff">
277
  <div style="font-size:48px;margin-bottom:16px">&#128065;</div>
@@ -3294,6 +3297,28 @@ controls.addEventListener('change', updateDetailLevel);
3294
  const clock = new THREE.Clock();
3295
  let frameCount = 0;
3296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3297
  renderer.setAnimationLoop(animate);
3298
  function animate() {
3299
  const dt = clock.getDelta();
@@ -3303,6 +3328,7 @@ function animate() {
3303
  updateFPMovement();
3304
  updateNPCFacing();
3305
  updatePlayerPosition();
 
3306
  } else {
3307
  controls.update();
3308
  updateCameraAnimation();
@@ -3531,7 +3557,7 @@ fpControls.addEventListener('lock', () => {
3531
  });
3532
  fpControls.addEventListener('unlock', () => {
3533
  document.getElementById('fp-crosshair').style.display = 'none';
3534
- if (fpMode) {
3535
  document.getElementById('fp-click-overlay').style.display = 'flex';
3536
  }
3537
  });
@@ -3636,16 +3662,25 @@ function startNpcChat(agentId) {
3636
  document.getElementById('chat-npc-name').textContent = name;
3637
  document.getElementById('chat-messages').innerHTML = '';
3638
  document.getElementById('chat-text').value = '';
 
 
3639
  document.getElementById('npc-chat').style.display = 'block';
3640
  fpControls.unlock();
 
 
3641
  addChatMsg('system', `${name} stops and turns to face you.`);
3642
  setTimeout(() => document.getElementById('chat-text').focus(), 100);
3643
  }
3644
 
3645
  function endNpcChat() {
3646
  if (isRecording) toggleMic();
 
3647
  chatTargetId = null;
3648
  chatMessages = [];
 
 
 
 
3649
  document.getElementById('npc-chat').style.display = 'none';
3650
  if (fpMode) {
3651
  const overlay = document.getElementById('fp-click-overlay');
 
272
  <div id="fp-hint" style="display:none;position:fixed;bottom:60px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.7);color:#fff;padding:8px 16px;border-radius:8px;font-size:13px;z-index:50;text-align:center">
273
  WASD β€” move &middot; Mouse β€” look &middot; E β€” talk to NPC &middot; ESC β€” exit
274
  </div>
275
+ <div id="fp-interact-prompt" style="display:none;position:fixed;top:55%;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.75);color:#4ecca3;padding:8px 18px;border-radius:8px;font-size:14px;z-index:55;pointer-events:none;border:1px solid rgba(78,204,163,0.3)">
276
+ Press <b>E</b> to talk
277
+ </div>
278
  <div id="fp-click-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:250;cursor:pointer;display:none;align-items:center;justify-content:center">
279
  <div style="text-align:center;color:#fff">
280
  <div style="font-size:48px;margin-bottom:16px">&#128065;</div>
 
3297
  const clock = new THREE.Clock();
3298
  let frameCount = 0;
3299
 
3300
+ const _interactRay = new THREE.Raycaster();
3301
+ _interactRay.far = 10;
3302
+ function updateInteractPrompt() {
3303
+ const prompt = document.getElementById('fp-interact-prompt');
3304
+ if (chatTargetId || !fpControls.isLocked) { prompt.style.display = 'none'; return; }
3305
+ _interactRay.setFromCamera(new THREE.Vector2(0, 0), fpCamera);
3306
+ const objs = [];
3307
+ for (const [, m] of agentMeshes) objs.push(m);
3308
+ const hits = _interactRay.intersectObjects(objs, true);
3309
+ if (hits.length > 0) {
3310
+ let p = hits[0].object;
3311
+ while (p.parent && !p.userData?.id) p = p.parent;
3312
+ if (p.userData?.id && p.userData.type === 'agent') {
3313
+ const name = p.userData.data?.name || p.userData.id;
3314
+ prompt.innerHTML = `Press <b>E</b> to talk to <b>${name}</b>`;
3315
+ prompt.style.display = 'block';
3316
+ return;
3317
+ }
3318
+ }
3319
+ prompt.style.display = 'none';
3320
+ }
3321
+
3322
  renderer.setAnimationLoop(animate);
3323
  function animate() {
3324
  const dt = clock.getDelta();
 
3328
  updateFPMovement();
3329
  updateNPCFacing();
3330
  updatePlayerPosition();
3331
+ if (frameCount % 10 === 0) updateInteractPrompt();
3332
  } else {
3333
  controls.update();
3334
  updateCameraAnimation();
 
3557
  });
3558
  fpControls.addEventListener('unlock', () => {
3559
  document.getElementById('fp-crosshair').style.display = 'none';
3560
+ if (fpMode && !chatTargetId) {
3561
  document.getElementById('fp-click-overlay').style.display = 'flex';
3562
  }
3563
  });
 
3662
  document.getElementById('chat-npc-name').textContent = name;
3663
  document.getElementById('chat-messages').innerHTML = '';
3664
  document.getElementById('chat-text').value = '';
3665
+ document.getElementById('fp-interact-prompt').style.display = 'none';
3666
+ document.getElementById('fp-click-overlay').style.display = 'none';
3667
  document.getElementById('npc-chat').style.display = 'block';
3668
  fpControls.unlock();
3669
+ const mesh = agentMeshes.get(agentId);
3670
+ if (mesh) mesh.userData.chatFrozen = true;
3671
  addChatMsg('system', `${name} stops and turns to face you.`);
3672
  setTimeout(() => document.getElementById('chat-text').focus(), 100);
3673
  }
3674
 
3675
  function endNpcChat() {
3676
  if (isRecording) toggleMic();
3677
+ const prevTarget = chatTargetId;
3678
  chatTargetId = null;
3679
  chatMessages = [];
3680
+ if (prevTarget) {
3681
+ const mesh = agentMeshes.get(prevTarget);
3682
+ if (mesh) mesh.userData.chatFrozen = false;
3683
+ }
3684
  document.getElementById('npc-chat').style.display = 'none';
3685
  if (fpMode) {
3686
  const overlay = document.getElementById('fp-click-overlay');