fix(studio): удалённая точка спавна не появляется при Play + скрыта из дерева
Баг: после удаления точки спавна она всё равно появлялась при запуске. Теперь _spawnEnabled синхронизируется в React (spawnEnabledUI) через onSceneChange/load/setSpawn/deleteSpawn; пункт «Точка спавна» скрыт из дерева когда удалён; player.start использует фолбэк (0,поверхность+2,0). Стартовая площадка теперь срабатывает (игрок не телепортируется на старый спавн). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
471af1cdeb
commit
7fc4ee94f6
@ -242,7 +242,7 @@ const HierarchyPanel = ({
|
|||||||
onSelectSound, onSelectPlayer, onSelectPlayerProps, onSelectFloor,
|
onSelectSound, onSelectPlayer, onSelectPlayerProps, onSelectFloor,
|
||||||
guiElements = [], onSelectGui, onCreateGui, onDeleteGui, onRenameGui, onMoveGuiZ, onSetGuiParent,
|
guiElements = [], onSelectGui, onCreateGui, onDeleteGui, onRenameGui, onMoveGuiZ, onSetGuiParent,
|
||||||
guiOverlayHidden = false, onToggleGuiOverlay,
|
guiOverlayHidden = false, onToggleGuiOverlay,
|
||||||
floorEnabled = true, onCreateFloor, onDeleteFloor, onDeleteSpawn,
|
floorEnabled = true, onCreateFloor, onDeleteFloor, onDeleteSpawn, spawnEnabled = true,
|
||||||
scripts = [], onSelectScript, onCreateScript, onDeleteScript,
|
scripts = [], onSelectScript, onCreateScript, onDeleteScript,
|
||||||
onRenameModel, onRenamePrimitive, onRenameScript,
|
onRenameModel, onRenamePrimitive, onRenameScript,
|
||||||
/**
|
/**
|
||||||
@ -781,7 +781,8 @@ const HierarchyPanel = ({
|
|||||||
/>
|
/>
|
||||||
{workspaceOpen && (
|
{workspaceOpen && (
|
||||||
<div style={{ paddingLeft: 8 }}>
|
<div style={{ paddingLeft: 8 }}>
|
||||||
{/* Точка спавна — кликабельная */}
|
{/* Точка спавна — кликабельная. Скрыта если удалена. */}
|
||||||
|
{spawnEnabled !== false && (
|
||||||
<div
|
<div
|
||||||
className={`${cl.item} ${selection?.type === 'spawn' ? cl.itemSelected : ''}`}
|
className={`${cl.item} ${selection?.type === 'spawn' ? cl.itemSelected : ''}`}
|
||||||
onClick={() => onSelectSpawn?.()}
|
onClick={() => onSelectSpawn?.()}
|
||||||
@ -792,6 +793,7 @@ const HierarchyPanel = ({
|
|||||||
<span className={cl.itemIcon} style={{ display: 'inline-flex' }}><Icon name="flag" size={14} /></span>
|
<span className={cl.itemIcon} style={{ display: 'inline-flex' }}><Icon name="flag" size={14} /></span>
|
||||||
<span className={cl.itemLabel}>Точка спавна</span>
|
<span className={cl.itemLabel}>Точка спавна</span>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Пол — псевдо-объект, если включён */}
|
{/* Пол — псевдо-объект, если включён */}
|
||||||
{floorEnabled && (
|
{floorEnabled && (
|
||||||
|
|||||||
@ -606,6 +606,7 @@ const KubikonEditor = () => {
|
|||||||
const [crosshair, setCrosshairUI] = useState('none');
|
const [crosshair, setCrosshairUI] = useState('none');
|
||||||
// Видимость пола в иерархии
|
// Видимость пола в иерархии
|
||||||
const [floorEnabled, setFloorEnabledUI] = useState(true);
|
const [floorEnabled, setFloorEnabledUI] = useState(true);
|
||||||
|
const [spawnEnabledUI, setSpawnEnabledUI] = useState(true);
|
||||||
// Табы над viewport (Roblox-style): «🎬 Сцена» + открытые скрипты
|
// Табы над viewport (Roblox-style): «🎬 Сцена» + открытые скрипты
|
||||||
const [openTabs, setOpenTabs] = useState([{ id: 'scene', kind: 'scene', title: 'Сцена' }]);
|
const [openTabs, setOpenTabs] = useState([{ id: 'scene', kind: 'scene', title: 'Сцена' }]);
|
||||||
const [activeTabId, setActiveTabId] = useState('scene');
|
const [activeTabId, setActiveTabId] = useState('scene');
|
||||||
@ -1354,6 +1355,8 @@ const KubikonEditor = () => {
|
|||||||
markDirty();
|
markDirty();
|
||||||
// Иерархия изменилась — interval пересоберёт списки на след. тике.
|
// Иерархия изменилась — interval пересоберёт списки на след. тике.
|
||||||
hierarchyDirtyRef.current = true;
|
hierarchyDirtyRef.current = true;
|
||||||
|
// Синк флага точки спавна (например после Delete-клавиши).
|
||||||
|
try { setSpawnEnabledUI(scene.hasSpawn?.() !== false); } catch (e) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Этап 5: подключаем API пользовательских моделей в BabylonScene,
|
// Этап 5: подключаем API пользовательских моделей в BabylonScene,
|
||||||
@ -1558,6 +1561,7 @@ const KubikonEditor = () => {
|
|||||||
const ch = sceneRef.current.getCrosshair?.();
|
const ch = sceneRef.current.getCrosshair?.();
|
||||||
if (ch) setCrosshairUI(ch);
|
if (ch) setCrosshairUI(ch);
|
||||||
setFloorEnabledUI(sceneRef.current.isFloorEnabled?.() !== false);
|
setFloorEnabledUI(sceneRef.current.isFloorEnabled?.() !== false);
|
||||||
|
setSpawnEnabledUI(sceneRef.current.hasSpawn?.() !== false);
|
||||||
const a = sceneRef.current.getAudioState?.();
|
const a = sceneRef.current.getAudioState?.();
|
||||||
if (a?.ambientId) setAmbientIdUI(a.ambientId);
|
if (a?.ambientId) setAmbientIdUI(a.ambientId);
|
||||||
if (a?.musicId) setMusicIdUI(a.musicId);
|
if (a?.musicId) setMusicIdUI(a.musicId);
|
||||||
@ -2112,6 +2116,7 @@ const KubikonEditor = () => {
|
|||||||
onPlayToggle={handlePlay}
|
onPlayToggle={handlePlay}
|
||||||
onSetSpawn={() => {
|
onSetSpawn={() => {
|
||||||
sceneRef.current?.setSpawnAtCamera();
|
sceneRef.current?.setSpawnAtCamera();
|
||||||
|
setSpawnEnabledUI(true);
|
||||||
}}
|
}}
|
||||||
hasSelection={!!selection}
|
hasSelection={!!selection}
|
||||||
onDuplicate={() => sceneRef.current?.duplicateSelected()}
|
onDuplicate={() => sceneRef.current?.duplicateSelected()}
|
||||||
@ -3245,6 +3250,7 @@ const KubikonEditor = () => {
|
|||||||
setActiveTool('select');
|
setActiveTool('select');
|
||||||
}}
|
}}
|
||||||
floorEnabled={floorEnabled}
|
floorEnabled={floorEnabled}
|
||||||
|
spawnEnabled={spawnEnabledUI}
|
||||||
onSelectFloor={() => {
|
onSelectFloor={() => {
|
||||||
sceneRef.current?.selection?.selectFloor?.();
|
sceneRef.current?.selection?.selectFloor?.();
|
||||||
setActiveTool('select');
|
setActiveTool('select');
|
||||||
@ -3312,6 +3318,7 @@ const KubikonEditor = () => {
|
|||||||
onDeleteSpawn={() => {
|
onDeleteSpawn={() => {
|
||||||
sceneRef.current?.deleteSpawn?.();
|
sceneRef.current?.deleteSpawn?.();
|
||||||
sceneRef.current?.clearSelection?.();
|
sceneRef.current?.clearSelection?.();
|
||||||
|
setSpawnEnabledUI(false);
|
||||||
markDirty();
|
markDirty();
|
||||||
}}
|
}}
|
||||||
onSelectLighting={() => {
|
onSelectLighting={() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user