diff --git a/src/engine/PlayerController.js b/src/engine/PlayerController.js index bd966e9..68dcc31 100644 --- a/src/engine/PlayerController.js +++ b/src/engine/PlayerController.js @@ -2212,13 +2212,23 @@ export class PlayerController { _setupInput() { const canvas = this.canvas; - // Задача 02: ЛКМ-клик НЕ берёт pointer-lock в third (курсор свободен для - // GUI/3D-табличек). Lock берётся только в perma-режимах (first/lock) — - // но там он уже взят в start(). В third lock включает только зажатая ПКМ. + // Задача 02 (как в студии): хелпер — режим с ПОСТОЯННЫМ pointer-lock. + const needPermLock = () => ( + this._cameraMode === 'first' || + this._cameraMode === 'lockfirst' || + this._cameraMode === 'sideview' || + this._shiftLock + ); + const onCanvasClick = () => { + // В UI-режиме клик не перехватывает мышь. if (this._uiCursorMode) return; - if (this._active && this._isPermaLockMode() - && document.pointerLockElement !== canvas) { + if (!this._active) return; + // Roblox-style: в third-person ЛКМ-клик НЕ лочит курсор (он остаётся + // свободным для GUI/3D-onClick). Lock запрашиваем ТОЛЬКО для режимов + // где курсор постоянно скрыт, и только если lock был снят. + if (!needPermLock()) return; + if (document.pointerLockElement !== canvas) { try { const p = canvas.requestPointerLock?.(); if (p && typeof p.catch === 'function') p.catch(() => {}); @@ -2227,31 +2237,33 @@ export class PlayerController { }; canvas.addEventListener('click', onCanvasClick); - // Задача 02: ПКМ-orbit — зажал ПКМ в third → lock + камера крутится, - // отпустил → курсор вернулся. В perma-режимах ПКМ не нужен. - const onRmbDown = (e) => { - if (e.button !== 2 || this._uiCursorMode) return; - if (!this._isPermaLockMode() && document.pointerLockElement !== canvas) { - this._rmbHeld = true; + // === ПКМ: в third-person удержание ПКМ запускает orbit-камеру === + // Зажал ПКМ → курсор скрыт, мышь крутит камеру. Отпустил → курсор вернулся. + const onCanvasMouseDownGlobal = (e) => { + if (!this._active || this._uiCursorMode) return; + if (e.button !== 2) return; // только ПКМ + if (needPermLock()) return; // в perma-режимах ПКМ ничего не делает + this._rmbHeld = true; + if (document.pointerLockElement !== canvas) { try { const p = canvas.requestPointerLock?.(); if (p && typeof p.catch === 'function') p.catch(() => {}); } catch (err) { /* ignore */ } } + e.preventDefault(); }; - const onRmbUp = (e) => { + const onWindowMouseUpGlobal = (e) => { if (e.button !== 2) return; - if (this._rmbHeld) { - this._rmbHeld = false; - if (!this._isPermaLockMode() && document.pointerLockElement === canvas) { - try { document.exitPointerLock(); } catch (err) { /* ignore */ } - } + if (!this._rmbHeld) return; + this._rmbHeld = false; + if (needPermLock()) return; + if (document.pointerLockElement === canvas) { + try { document.exitPointerLock(); } catch (err) { /* ignore */ } } }; - const onCtxMenu = (e) => { if (!this._uiCursorMode) e.preventDefault(); }; - canvas.addEventListener('mousedown', onRmbDown); - document.addEventListener('mouseup', onRmbUp); - canvas.addEventListener('contextmenu', onCtxMenu); + canvas.addEventListener('mousedown', onCanvasMouseDownGlobal); + window.addEventListener('mouseup', onWindowMouseUpGlobal); + canvas.addEventListener('contextmenu', (e) => { if (this._active) e.preventDefault(); }); // === UI-режим: mousedown / mouseup → callback (для drag-игр) === const onCanvasMouseDown = (e) => { @@ -2343,18 +2355,26 @@ export class PlayerController { let wasLocked = false; const onPointerLockChange = () => { const locked = document.pointerLockElement === canvas; - this._applyCursorVisibility(); // задача 02: вернуть/скрыть курсор + this._applyCursorVisibility?.(); // задача 02: вернуть/скрыть курсор if (locked) { wasLocked = true; + this._rmbHeld = true; // если попали в lock — ПКМ удерживается } else if (wasLocked && this._active) { + // pointer-lock снят. Причин три: + // 1) пользователь в UI-режиме (game.input.setCursorMode('ui')) + // 2) ПКМ отпущена в third-person (orbit-камера завершена) + // 3) Esc → выход из Play (если был в first/lockfirst/sideview/shift) wasLocked = false; - if (this._uiCursorMode) return; - // Задача 02: в third потеря lock = отпустили ПКМ (orbit) ИЛИ - // вышли зумом из first — это НЕ выход из Play. Выход (Esc) только - // из perma-режимов с постоянным lock (first/lockfirst/shift-lock). - if (this._rmbHeld) { this._rmbHeld = false; return; } - if (this._cameraMode === 'third' || this._cameraMode === 'front') return; - if (this._onExitRequest) this._onExitRequest(); + this._rmbHeld = false; + if (this._uiCursorMode) { this._applyCursorVisibility?.(); return; } + if (needPermLock()) { + // Был режим с постоянным lock'ом и его сняли (Esc) → выход. + if (this._onExitRequest) this._onExitRequest(); + } else { + // Third-person: просто отпустили ПКМ. Остаёмся в Play, + // курсор вернулся — это НЕ повод открывать меню. + this._applyCursorVisibility?.(); + } } }; document.addEventListener('pointerlockchange', onPointerLockChange);