diff --git a/src/editor/KubikonEditor.jsx b/src/editor/KubikonEditor.jsx index de3b705..b54eb7d 100644 --- a/src/editor/KubikonEditor.jsx +++ b/src/editor/KubikonEditor.jsx @@ -800,16 +800,18 @@ const KubikonEditor = () => { } } - // 2) Добавляем скрипты кита. + // 2) Добавляем скрипты кита — с понятным именем (название кита). if (Array.isArray(kit.scripts)) { - for (const sc of kit.scripts) { + kit.scripts.forEach((sc, idx) => { const sid = `script_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`; + // Имя = название кита (+ номер, если скриптов несколько). + const nm = kit.scripts.length > 1 ? `${kit.name} (${idx + 1})` : kit.name; if (sc.attachTo === 'on-target' && firstPrimId != null) { - s.upsertScript(sid, sc.code, { kind: 'primitive', id: firstPrimId }); + s.upsertScript(sid, sc.code, { kind: 'primitive', id: firstPrimId }, nm); } else { - s.upsertScript(sid, sc.code, null); // глобальный + s.upsertScript(sid, sc.code, null, nm); // глобальный } - } + }); } markDirty(); @@ -3171,7 +3173,12 @@ const KubikonEditor = () => { } } const tpl = normalized ? NEW_OBJECT_SCRIPT_TEMPLATE : NEW_SCRIPT_TEMPLATE; - sceneRef.current?.upsertScript(id, tpl, normalized); + // Понятное имя по умолчанию (а не сырой id). + const existing = sceneRef.current?.getScripts?.() || []; + const nm = normalized + ? `Скрипт объекта ${existing.filter(s => s.target && s.target !== 'game').length + 1}` + : `Скрипт ${existing.filter(s => !s.target || s.target === 'game').length + 1}`; + sceneRef.current?.upsertScript(id, tpl, normalized, nm); markDirty(); setScriptsList(sceneRef.current?.getScripts?.() || []); sceneRef.current?.selection?.selectScript?.(id); diff --git a/src/editor/engine/BabylonScene.js b/src/editor/engine/BabylonScene.js index c34478d..bfda811 100644 --- a/src/editor/engine/BabylonScene.js +++ b/src/editor/engine/BabylonScene.js @@ -6392,19 +6392,21 @@ export class BabylonScene { } /** Установить код одного скрипта по id. Если id нет — создать новый. */ - upsertScript(id, code, target = undefined) { + upsertScript(id, code, target = undefined, name = undefined) { const i = this._scripts.findIndex(s => s.id === id); if (i >= 0) { this._scripts[i] = { ...this._scripts[i], code, ...(target !== undefined ? { target } : {}), + ...(name !== undefined ? { name } : {}), }; } else { this._scripts.push({ id: id || `script_${Date.now()}`, code, target: target !== undefined ? target : null, + name: name || null, }); } // Скрипты — часть сцены: фиксируем в истории, иначе undo откатит diff --git a/src/editor/engine/ScriptSandboxWorker.js b/src/editor/engine/ScriptSandboxWorker.js index 8ed1488..c1906b1 100644 --- a/src/editor/engine/ScriptSandboxWorker.js +++ b/src/editor/engine/ScriptSandboxWorker.js @@ -742,6 +742,18 @@ function _buildSelfApi() { _send('self.move', { target: _target, x: nx, y: ny, z: nz }); } }, + /** + * Повернуть объект-носитель вокруг вертикальной оси Y на угол ry (радианы). + * game.onTick((dt) => { a += dt; game.self.rotate(a); }); + */ + rotate(ry) { + const r = Number(ry); + if (!Number.isFinite(r)) return; + const k = _target.kind; + const id = _target.id ?? _target.ref; + _send('scene.rotate', { kind: k, id, ref: (k && id != null) ? (k + ':' + id) : undefined, rotationY: r }); + }, + rotateY(ry) { this.rotate(ry); }, delete() { _send('self.delete', { target: _target }); },