fix(studio): game.self.rotate + понятные имена скриптов китов

- game.self.rotate(ry)/rotateY(ry) добавлен в worker (слал scene.rotate с
  ref объекта-носителя). Кит «Вращающийся объект» падал 'game.self.rotate is
  not a function' каждый кадр в onTick — теперь крутится.
- upsertScript принимает name; вставка кита даёт скрипту имя = название кита
  (раньше в дереве был сырой id script_mq03...). Ручное создание скрипта тоже
  даёт «Скрипт N» / «Скрипт объекта N» вместо id.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
min 2026-06-05 02:05:17 +03:00
parent 781c3cf945
commit df1647019d
3 changed files with 28 additions and 7 deletions

View File

@ -800,16 +800,18 @@ const KubikonEditor = () => {
} }
} }
// 2) Добавляем скрипты кита. // 2) Добавляем скрипты кита с понятным именем (название кита).
if (Array.isArray(kit.scripts)) { 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 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) { 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 { } else {
s.upsertScript(sid, sc.code, null); // глобальный s.upsertScript(sid, sc.code, null, nm); // глобальный
}
} }
});
} }
markDirty(); markDirty();
@ -3171,7 +3173,12 @@ const KubikonEditor = () => {
} }
} }
const tpl = normalized ? NEW_OBJECT_SCRIPT_TEMPLATE : NEW_SCRIPT_TEMPLATE; 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(); markDirty();
setScriptsList(sceneRef.current?.getScripts?.() || []); setScriptsList(sceneRef.current?.getScripts?.() || []);
sceneRef.current?.selection?.selectScript?.(id); sceneRef.current?.selection?.selectScript?.(id);

View File

@ -6392,19 +6392,21 @@ export class BabylonScene {
} }
/** Установить код одного скрипта по id. Если id нет — создать новый. */ /** Установить код одного скрипта по id. Если id нет — создать новый. */
upsertScript(id, code, target = undefined) { upsertScript(id, code, target = undefined, name = undefined) {
const i = this._scripts.findIndex(s => s.id === id); const i = this._scripts.findIndex(s => s.id === id);
if (i >= 0) { if (i >= 0) {
this._scripts[i] = { this._scripts[i] = {
...this._scripts[i], ...this._scripts[i],
code, code,
...(target !== undefined ? { target } : {}), ...(target !== undefined ? { target } : {}),
...(name !== undefined ? { name } : {}),
}; };
} else { } else {
this._scripts.push({ this._scripts.push({
id: id || `script_${Date.now()}`, id: id || `script_${Date.now()}`,
code, code,
target: target !== undefined ? target : null, target: target !== undefined ? target : null,
name: name || null,
}); });
} }
// Скрипты — часть сцены: фиксируем в истории, иначе undo откатит // Скрипты — часть сцены: фиксируем в истории, иначе undo откатит

View File

@ -742,6 +742,18 @@ function _buildSelfApi() {
_send('self.move', { target: _target, x: nx, y: ny, z: nz }); _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() { delete() {
_send('self.delete', { target: _target }); _send('self.delete', { target: _target });
}, },