From 909af7a5d8e2cab0e8170994149e178ab170efdd Mon Sep 17 00:00:00 2001 From: min Date: Sun, 7 Jun 2026 13:49:07 +0300 Subject: [PATCH] =?UTF-8?q?fix(player):=20=D0=BF=D0=BE=D1=80=D1=82=20?= =?UTF-8?q?=E2=80=94=20NPC=20pickable+npcId=20=D0=B4=D0=BB=D1=8F=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BF=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B9=20=D0=BE=D1=80?= =?UTF-8?q?=D1=83=D0=B6=D0=B8=D1=8F=20(=D0=B0=D0=B2=D1=82=D0=BE-floater)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- src/engine/NpcManager.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/engine/NpcManager.js b/src/engine/NpcManager.js index 8ee0017..cf1c597 100644 --- a/src/engine/NpcManager.js +++ b/src/engine/NpcManager.js @@ -161,6 +161,19 @@ export class NpcManager { r15Animator, }; this.npcs.set(id, npc); + // Пометить меши NPC для попаданий оружия (бластер/меч): pickable + npcId + // в metadata. Без pickable raycast оружия проходит сквозь NPC (задача 40). + try { + const root = npc.data && npc.data.rootMesh; + if (root) { + root.isPickable = true; + root.metadata = Object.assign({}, root.metadata, { npcId: id }); + for (const m of root.getChildMeshes(false)) { + m.isPickable = true; + m.metadata = Object.assign({}, m.metadata, { npcId: id }); + } + } + } catch (e) { /* ignore */ } return id; } @@ -309,16 +322,21 @@ export class NpcManager { * содержат hit-меш (или предка). Вызывает damage() → авто-floater. */ damageByMesh(mesh, amount) { if (!mesh) return false; + let m = mesh; + for (let i = 0; i < 8 && m; i++) { + const nid = m.metadata && m.metadata.npcId; + if (nid != null && this.npcs.has(nid)) { this.damage(nid, amount); return true; } + m = m.parent; + } for (const npc of this.npcs.values()) { if (npc.dead) continue; const root = npc.data && npc.data.rootMesh; if (!root) continue; - let m = mesh, hit = false; - for (let i = 0; i < 8 && m; i++) { // вверх по иерархии до rootMesh - if (m === root) { hit = true; break; } - m = m.parent; + let mm = mesh; + for (let i = 0; i < 8 && mm; i++) { + if (mm === root) { this.damage(npc.id, amount); return true; } + mm = mm.parent; } - if (hit) { this.damage(npc.id, amount); return true; } } return false; }