From fe8b6b5b38191cc1947bcea69fe83142df47b8f2 Mon Sep 17 00:00:00 2001 From: min Date: Fri, 5 Jun 2026 19:36:18 +0300 Subject: [PATCH] =?UTF-8?q?fix(studio):=20NPC-=D0=BA=D0=B8=D1=82=D1=8B=20(?= =?UTF-8?q?robot=E2=86=92character-a),=20=D0=B4=D0=B2=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BA=D0=BE=D0=B4=D1=83=20=D0=BF=D0=BB=D0=B0?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=20=D1=80=D0=B0=D1=81=D0=BF=D0=B0=D1=85=D0=B8?= =?UTF-8?q?=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) NPC-преследователь/торговец/волна: spawnNpc('robot') → 'character-a' (модели 'robot' не существует в ModelTypes → spawnNpc возвращал null → ошибка). 2) Дверь по коду: верный код → ПЛАВНОЕ открытие вокруг петли (как дверь по E), декор-панели вращаются вместе с полотном. Раньше полотно уезжало вниз, декор оставался. Co-Authored-By: Claude Opus 4.8 --- src/editor/engine/GameplayKits.js | 61 ++++++++++++++++++------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/editor/engine/GameplayKits.js b/src/editor/engine/GameplayKits.js index 93518b9..f6d8cee 100644 --- a/src/editor/engine/GameplayKits.js +++ b/src/editor/engine/GameplayKits.js @@ -591,38 +591,49 @@ game.hud.setHpVisible(false);` }], { type: 'cube', x: 0, y: 4.1, z: 0, sx: 0.4, sy: 0.4, sz: 3.5, color: '#3a4250', material: 'metal', name: 'Перемычка' }, ], scripts: [{ attachTo: 'on-target', code: -`// Дверь по коду 1234. Поле ввода появляется ТОЛЬКО когда игрок рядом. +`// Дверь по коду 1234. Поле ввода появляется ТОЛЬКО рядом. Верный код → +// дверь ПЛАВНО распахивается вокруг петли (вместе с панелями). const CODE = '1234'; const p0 = game.self.position; +const halfW = 1.3; // полуширина полотна (sz=2.6) +const hingeX = p0.x, hingeZ = p0.z - halfW; const RADIUS = 6; -let opened = false, near = false, inp = null; -game.ui.set('codehint', '', {}); -game.onTick(() => { +let opened = false, near = false, cur = 0, target = 0; +const SPEED = Math.PI; // ~0.5с на 90° + +// Декор полотна — двигается вместе с дверью. +const decorNames = ['Панель двери', 'Панель двери низ', 'Кодовая панель']; +const decor = []; +for (const nm of decorNames) { + const o = game.scene.findOne(nm); + if (o && o.position) decor.push({ obj:o, dx:o.position.x-p0.x, dy:o.position.y-p0.y, dz:o.position.z-p0.z }); +} +function rotY(lx, lz, a){ const s=Math.sin(a),c=Math.cos(a); return { x: lx*c+lz*s, z: -lx*s+lz*c }; } +function place(a){ + const pc = rotY(0, halfW, a); + const cx = hingeX + pc.x, cz = hingeZ + pc.z; + game.self.move(cx, p0.y, cz); game.self.rotate(a); + for (const d of decor){ const r = rotY(d.dx, d.dz, a); d.obj.move(cx+r.x, p0.y+d.dy, cz+r.z); if (d.obj.rotate) d.obj.rotate(a); } +} +game.onTick((dt) => { + if (cur !== target){ const st=SPEED*dt; cur = Math.abs(target-cur)<=st ? target : cur+Math.sign(target-cur)*st; place(cur); } if (opened) return; + // Поле ввода появляется/прячется по дистанции. const pl = game.player.position; - const dx = pl.x - p0.x, dz = pl.z - p0.z; - const d = Math.sqrt(dx*dx + dz*dz); - if (d < RADIUS && !near) { - near = true; - inp = game.gui.create('textbox', { id:'codein', x:50, y:86, w:24, h:8, anchor:'center', placeholder:'Код...', textSize:20 }); - game.ui.set('codehint', '🔢 Введи код двери и нажми Enter', {x:50,y:78,anchor:'bottom',color:'#fff',size:16}); - } else if (d >= RADIUS && near) { - near = false; - if (inp) game.gui.remove('codein'); - game.ui.set('codehint', '', {}); - } + const d = Math.sqrt((pl.x-p0.x)**2 + (pl.z-p0.z)**2); + if (d < RADIUS && !near){ near = true; + game.gui.create('textbox', { id:'codein', x:50, y:86, w:24, h:8, anchor:'center', placeholder:'Код...', textSize:20 }); + game.ui.set('codehint', '🔢 Введи код двери (1234) и нажми Enter', {x:50,y:78,anchor:'bottom',color:'#fff',size:16}); } + else if (d >= RADIUS && near){ near = false; game.gui.remove('codein'); game.ui.set('codehint','',{}); } }); game.gui.onSubmit('codein', (text) => { if (opened) return; - if (String(text).trim() === CODE) { - opened = true; - game.self.move(p0.x, p0.y - 4.2, p0.z); // дверь уезжает вниз (открыта) + if (String(text).trim() === CODE){ + opened = true; target = Math.PI/2; // плавно распахнуть game.gui.remove('codein'); - game.ui.set('codehint', '✓ Открыто!', {x:50,y:78,anchor:'bottom',color:'#36d57a',size:18}); - game.after(2, () => game.ui.set('codehint', '', {})); - } else { - game.ui.set('codehint', '✗ Неверный код', {x:50,y:78,anchor:'bottom',color:'#ff5555',size:18}); - } + game.ui.set('codehint','✓ Открыто!', {x:50,y:78,anchor:'bottom',color:'#36d57a',size:18}); + game.after(2, () => game.ui.set('codehint','',{})); + } else game.ui.set('codehint','✗ Неверный код', {x:50,y:78,anchor:'bottom',color:'#ff5555',size:18}); });` }], }, { @@ -690,7 +701,7 @@ game.onTick(() => { icon: 'chase', category: 'npc', scripts: [{ attachTo: 'global', code: `// Спавним NPC, который преследует игрока. -const enemy = game.scene.spawnNpc('robot', { x: 8, z: 8, name: 'Охотник', speed: 4 }); +const enemy = game.scene.spawnNpc('character-a', { x: 8, z: 8, name: 'Охотник', speed: 4 }); if (enemy && enemy.follow) enemy.follow('player');` }], }, { @@ -760,7 +771,7 @@ game.self.onClick(() => { `// Каждые 5с спавнит 2 врагов из точки портала, они идут к игроку. const p = game.self.position; function wave(){ - for (let i=0;i<2;i++){ const e = game.scene.spawnNpc('robot', { x:p.x+(Math.random()-0.5)*2, z:p.z+(Math.random()-0.5)*2, name:'Враг', speed:3 }); + for (let i=0;i<2;i++){ const e = game.scene.spawnNpc('character-a', { x:p.x+(Math.random()-0.5)*2, z:p.z+(Math.random()-0.5)*2, name:'Враг', speed:3 }); if (e && e.follow) e.follow('player'); } } game.after(2, wave); game.every(5, wave);` }],