From 7b869c83bd7817061388fac8eed032fba207364c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=98=D0=9D?= Date: Sat, 30 May 2026 12:32:34 +0300 Subject: [PATCH] =?UTF-8?q?fix(player):=20=D0=BA=D0=BB=D0=B8=D0=BA=20?= =?UTF-8?q?=D0=BF=D0=BE=203D-=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=87=D0=BA?= =?UTF-8?q?=D0=B0=D0=BC=20=D0=B2=20third-person=20(=D1=81=D0=B2=D0=BE?= =?UTF-8?q?=D0=B1=D0=BE=D0=B4=D0=BD=D1=8B=D0=B9=20=D0=BA=D1=83=D1=80=D1=81?= =?UTF-8?q?=D0=BE=D1=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _handlePlayClick пикал билборд из ЦЕНТРА экрана (w/2,h/2) — верно только при pointer-lock. В third курсор свободен, юзер кликает мышью НЕ в центре → pick промахивался, кнопки табличек не нажимались (Ферма 1981 и др). Фикс: onMouseDown передаёт реальные canvas-координаты клика в _handlePlayClick(clickX,clickY); при locked — центр, иначе — точка клика. Добавлен console.log [billboard] для диагностики попадания. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/engine/BabylonScene.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) 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'); } } }