diff --git a/src/engine/BabylonScene.js b/src/engine/BabylonScene.js index 0b19b10..ecb9c50 100644 --- a/src/engine/BabylonScene.js +++ b/src/engine/BabylonScene.js @@ -2183,8 +2183,12 @@ export class BabylonScene { const onMouseDown = (e) => { if (this._isPlaying) { // В Play-режиме ЛКМ — клик игрока в forward-направлении. - // Pointer Lock — курсор всё равно в центре экрана. - if (e.button === 0) this._handlePlayClick(); + // При pointer-lock курсор в центре; в third (свободный курсор) + // передаём реальные координаты клика для pick по табличкам. + if (e.button === 0) { + const r = canvas.getBoundingClientRect(); + this._handlePlayClick(e.clientX - r.left, e.clientY - r.top); + } return; } // Обновляем pointer координаты для raycast и Gizmo @@ -2913,7 +2917,7 @@ export class BabylonScene { * - в self-обработчики скриптов (routeEvent с target) * - в глобальные обработчики (game.onClick) с event.target */ - _handlePlayClick() { + _handlePlayClick(clickX, clickY) { if (!this._isPlaying) return; // Мультиплеер-выстрел: если у сцены есть mpSync, шлём 'shoot' серверу. @@ -2936,12 +2940,17 @@ export class BabylonScene { if (!this.gameRuntime) return; // === Задача 01: клик по КНОПКЕ 3D-таблички (billboard) === - // Пикаем из центра экрана (как _pickFromCenter — в Play обычно - // pointer-lock). Если попали в кнопку таблички → fireClick и выходим. + // При pointer-lock (first/shift-lock) курсор в центре экрана → пикаем + // из центра. В third курсор СВОБОДНЫЙ → пикаем по реальным координатам + // клика (clickX/clickY переданы из onMouseDown). Без этого клик по + // табличке мышью в third промахивался — кнопки не нажимались. if (this.billboardUiManager && this.primitiveManager) { + const locked = (document.pointerLockElement === this.canvas); const w = this.engine?.getRenderWidth?.() || this.canvas.width; const h = this.engine?.getRenderHeight?.() || this.canvas.height; - const bpick = this.scene.pick(w / 2, h / 2, (m) => + const px = locked ? w / 2 : (Number.isFinite(clickX) ? clickX : w / 2); + const py = locked ? h / 2 : (Number.isFinite(clickY) ? clickY : h / 2); + const bpick = this.scene.pick(px, py, (m) => m && m.metadata && m.metadata.primitiveId != null && this.primitiveManager.instances.get(m.metadata.primitiveId)?.type === 'billboard'); if (bpick && bpick.hit && bpick.pickedMesh) { @@ -2949,10 +2958,16 @@ export class BabylonScene { const uv = bpick.getTextureCoordinates ? bpick.getTextureCoordinates() : null; if (bdata && uv) { const buttonId = this.billboardUiManager.pickButtonAt(bdata, uv.x, uv.y); + console.log('[billboard] клик id=' + bpick.pickedMesh.metadata.primitiveId + + ' uv=(' + uv.x.toFixed(2) + ',' + uv.y.toFixed(2) + ') buttonId=' + buttonId + + ' locked=' + locked); if (buttonId) { this.billboardUiManager.fireClick(bdata, buttonId); return; // клик по табличке обработан } + } else { + console.log('[billboard] попал в табличку id=' + + bpick.pickedMesh.metadata.primitiveId + ' но нет UV'); } } }