diff --git a/src/editor/engine/GameplayKits.js b/src/editor/engine/GameplayKits.js index 387f471..d3517d3 100644 --- a/src/editor/engine/GameplayKits.js +++ b/src/editor/engine/GameplayKits.js @@ -191,6 +191,89 @@ game.self.onInteract(() => { game.after(3, () => game.ui.set('loot', '')); }, { text: 'Открыть сундук', key: 'f', distance: 4 });` }], }, + + // ===== Партия 1 из Вики (киты 13-17) ===== + + { + id: 'trampoline', + name: 'Батут (пружина)', + desc: 'Яркая платформа-батут — наступи на неё, и игрока подбросит высоко вверх. (Вики: «Прыжок-пружина»)', + icon: 'arrow-up', category: 'movement', + prims: [{ type: 'cylinder', x: 0, y: 0.3, z: 0, sx: 3, sy: 0.6, sz: 3, color: '#ff3c8e', material: 'neon', name: 'Батут' }], + scripts: [{ attachTo: 'on-target', code: +`// Батут: касание → подброс игрока вверх. +game.self.onTouch(() => { + game.player.setVy(20); // вертикальный импульс (как трамплин) +});` }], + }, + { + id: 'speed-pad', + name: 'Лента ускорения', + desc: 'Жёлтая плита-ускоритель — наступи, и игрок бежит быстрее несколько секунд. (Вики: «бусты скорости»)', + icon: 'zap', category: 'movement', + prims: [{ type: 'cube', x: 0, y: 0.1, z: 0, sx: 3, sy: 0.2, sz: 5, color: '#ffd23a', material: 'neon', name: 'Лента ускорения', canCollide: false }], + scripts: [{ attachTo: 'on-target', code: +`// Лента ускорения: касание → x2 скорости на 3 секунды. +let boosting = false; +game.self.onTouch(() => { + if (boosting) return; + boosting = true; + game.player.setSpeed(2.0); + game.ui.set('boost', '⚡ Ускорение!', { x: 50, y: 80, anchor: 'bottom', color: '#ffd23a', size: 18 }); + game.after(3, () => { game.player.setSpeed(1.0); game.ui.set('boost', ''); boosting = false; }); +});` }], + }, + { + id: 'teleport-portal', + name: 'Портал-телепорт', + desc: 'Два синих портала. Вошёл в портал — мгновенно переносишься ко второму. Поставь второй портал где нужно. (Вики: «секретный путь»)', + icon: 'sparkles', category: 'movement', + prims: [ + { type: 'cylinder', x: 0, y: 1.5, z: 0, sx: 0.4, sy: 3, sz: 3, color: '#4d6bff', material: 'neon', name: 'Портал A' }, + { type: 'cylinder', x: 8, y: 1.5, z: 0, sx: 0.4, sy: 3, sz: 3, color: '#4dffd6', material: 'neon', name: 'Портал B', canCollide: false }, + ], + scripts: [{ attachTo: 'on-target', code: +`// Портал A: касание → телепорт к порталу B (стоит правее на +8 по X). +// Передвинь «Портал B» куда нужно и поправь координаты ниже. +let cd = false; +game.self.onTouch(() => { + if (cd) return; cd = true; + const p = game.self.position; + game.player.teleport(p.x + 8, p.y + 1, p.z); // к месту портала B + game.after(1, () => { cd = false; }); +});` }], + }, + { + id: 'disappearing-platform', + name: 'Исчезающая платформа', + desc: 'Платформа пропадает под ногами через секунду после касания и возвращается через 3с. (Вики: «Не упади», «Падающий мост»)', + icon: 'square', category: 'world', + prims: [{ type: 'cube', x: 0, y: 0.25, z: 0, sx: 4, sy: 0.5, sz: 4, color: '#e06a3c', material: 'matte', name: 'Исчезающая платформа' }], + scripts: [{ attachTo: 'on-target', code: +`// Исчезающая платформа: наступил → через 1с пропадает, через 3с возвращается. +let busy = false; +game.self.onTouch(() => { + if (busy) return; busy = true; + game.after(1, () => { game.self.setVisible(false); game.self.setCollide(false); }); + game.after(3, () => { game.self.setVisible(true); game.self.setCollide(true); busy = false; }); +});` }], + }, + { + id: 'door-button', + name: 'Дверь по кнопке E', + desc: 'Дверь + кнопка: подойди, нажми E — дверь уезжает в сторону и открывает проход. (Вики: «Кнопка-открывашка»)', + icon: 'door', category: 'world', + prims: [{ type: 'cube', x: 0, y: 2, z: 0, sx: 1, sy: 4, sz: 3, color: '#8a5a3c', material: 'matte', name: 'Дверь' }], + scripts: [{ attachTo: 'on-target', code: +`// Дверь по E: открыта/закрыта — уезжает вниз и возвращается. +let open = false; +const p0 = game.self.position; // закрытое положение +game.self.onInteract(() => { + open = !open; + if (open) game.self.move(p0.x, p0.y - 4.2, p0.z); // уехала вниз (открыта) + else game.self.move(p0.x, p0.y, p0.z); // вернулась (закрыта) +}, { text: open ? 'Закрыть' : 'Открыть', key: 'e', distance: 5 });` }], + }, ]; /** Найти кит по id. */ diff --git a/src/editor/engine/ScriptSandboxWorker.js b/src/editor/engine/ScriptSandboxWorker.js index c1906b1..468051a 100644 --- a/src/editor/engine/ScriptSandboxWorker.js +++ b/src/editor/engine/ScriptSandboxWorker.js @@ -754,6 +754,18 @@ function _buildSelfApi() { _send('scene.rotate', { kind: k, id, ref: (k && id != null) ? (k + ':' + id) : undefined, rotationY: r }); }, rotateY(ry) { this.rotate(ry); }, + /** Показать/скрыть объект-носитель. */ + setVisible(vis) { + const k = _target.kind; + const id = _target.id ?? _target.ref; + _send('scene.setVisible', { kind: k, id, ref: (k && id != null) ? (k + ':' + id) : undefined, visible: !!vis }); + }, + /** Включить/выключить столкновения объекта-носителя (проходимость). */ + setCollide(can) { + const k = _target.kind; + const id = _target.id ?? _target.ref; + _send('scene.setCollide', { kind: k, id, ref: (k && id != null) ? (k + ':' + id) : undefined, canCollide: !!can }); + }, delete() { _send('self.delete', { target: _target }); },