fix(studio): бластер от 3-го лица стреляет в точку клика, а не в центр камеры
При свободном курсоре (нет pointer-lock, 3-е лицо) выстрел шёл из getForwardRay (фокус камеры). Теперь onDown берёт координаты клика → setAimScreenPoint → луч через точку клика; onMove обновляет _holdAim для авто-огня при удержании. При pointer-lock (1-е лицо, курсор в центре) — прежнее поведение (центр). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e4fdd91b12
commit
931d53b4d9
@ -90,6 +90,18 @@ export class WeaponSystem {
|
|||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
// Если UI-режим курсора — не стреляем (мышь работает по GUI)
|
// Если UI-режим курсора — не стреляем (мышь работает по GUI)
|
||||||
if (this.scene3d?.player?.isUiCursorMode?.()) return;
|
if (this.scene3d?.player?.isUiCursorMode?.()) return;
|
||||||
|
// Если курсор СВОБОДЕН (нет pointer-lock — обычно 3-е лицо) — стреляем
|
||||||
|
// ТУДА, КУДА КЛИКНУЛИ, а не в центр камеры. При pointer-lock курсор в
|
||||||
|
// центре экрана → используем прицел камеры (aim не задаём).
|
||||||
|
if (document.pointerLockElement !== canvas) {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const cx = (e.clientX != null ? e.clientX : 0) - rect.left;
|
||||||
|
const cy = (e.clientY != null ? e.clientY : 0) - rect.top;
|
||||||
|
if (cx >= 0 && cy >= 0 && cx <= rect.width && cy <= rect.height) {
|
||||||
|
this.setAimScreenPoint(cx * (canvas.width / rect.width),
|
||||||
|
cy * (canvas.height / rect.height));
|
||||||
|
}
|
||||||
|
}
|
||||||
this._mouseDown = true;
|
this._mouseDown = true;
|
||||||
this._tryFire();
|
this._tryFire();
|
||||||
};
|
};
|
||||||
@ -97,14 +109,28 @@ export class WeaponSystem {
|
|||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
this._mouseDown = false;
|
this._mouseDown = false;
|
||||||
};
|
};
|
||||||
|
// При свободном курсоре (3-е лицо) запоминаем позицию мыши — чтобы
|
||||||
|
// авто-огонь при удержании ЛКМ продолжал стрелять в точку курсора.
|
||||||
|
const onMove = (e) => {
|
||||||
|
if (!this._mouseDown) return;
|
||||||
|
if (document.pointerLockElement === canvas) return;
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const cx = (e.clientX != null ? e.clientX : 0) - rect.left;
|
||||||
|
const cy = (e.clientY != null ? e.clientY : 0) - rect.top;
|
||||||
|
if (cx >= 0 && cy >= 0 && cx <= rect.width && cy <= rect.height) {
|
||||||
|
this._holdAim = { x: cx * (canvas.width / rect.width), y: cy * (canvas.height / rect.height) };
|
||||||
|
}
|
||||||
|
};
|
||||||
const onKey = (e) => {
|
const onKey = (e) => {
|
||||||
if (e.code === 'KeyR') this.reload();
|
if (e.code === 'KeyR') this.reload();
|
||||||
};
|
};
|
||||||
canvas.addEventListener('mousedown', onDown);
|
canvas.addEventListener('mousedown', onDown);
|
||||||
window.addEventListener('mouseup', onUp);
|
window.addEventListener('mouseup', onUp);
|
||||||
|
window.addEventListener('mousemove', onMove);
|
||||||
window.addEventListener('keydown', onKey);
|
window.addEventListener('keydown', onKey);
|
||||||
this._listeners.push({ target: canvas, type: 'mousedown', fn: onDown });
|
this._listeners.push({ target: canvas, type: 'mousedown', fn: onDown });
|
||||||
this._listeners.push({ target: window, type: 'mouseup', fn: onUp });
|
this._listeners.push({ target: window, type: 'mouseup', fn: onUp });
|
||||||
|
this._listeners.push({ target: window, type: 'mousemove', fn: onMove });
|
||||||
this._listeners.push({ target: window, type: 'keydown', fn: onKey });
|
this._listeners.push({ target: window, type: 'keydown', fn: onKey });
|
||||||
|
|
||||||
// Регистрируем перед-кадровый хук для авто-стрельбы (если auto=true)
|
// Регистрируем перед-кадровый хук для авто-стрельбы (если auto=true)
|
||||||
@ -583,7 +609,12 @@ export class WeaponSystem {
|
|||||||
// (для tap-to-shoot на мобиле). Точка применяется один раз.
|
// (для tap-to-shoot на мобиле). Точка применяется один раз.
|
||||||
let hit = null;
|
let hit = null;
|
||||||
let ray;
|
let ray;
|
||||||
const aim = this._aimScreenPoint;
|
// aim: разовый клик (_aimScreenPoint) или удержание по курсору (_holdAim,
|
||||||
|
// только когда курсор свободен — нет pointer-lock).
|
||||||
|
let aim = this._aimScreenPoint;
|
||||||
|
if (!aim && this._holdAim && document.pointerLockElement !== this.scene3d?.canvas) {
|
||||||
|
aim = this._holdAim;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (aim) {
|
if (aim) {
|
||||||
ray = this.scene.createPickingRay(aim.x, aim.y, null, camera);
|
ray = this.scene.createPickingRay(aim.x, aim.y, null, camera);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user