faster selection in editor

This commit is contained in:
azykov@mail.ru 2026-06-03 18:38:22 +03:00
parent 4e7b44dc57
commit 8575327af8
No known key found for this signature in database
2 changed files with 39 additions and 14 deletions

View File

@ -13,24 +13,51 @@ type ObjectEditorViewProps = {
object: Runtime<ObjectInstance>; object: Runtime<ObjectInstance>;
} }
export const ObjectEditorView = observer(function ({ object }: ObjectEditorViewProps) { type SelectionOverlayProps = {
const groupRef = useRef<Group>(null); objectId: string;
groupRef: RefObject<Group | null>;
const objectType = state.world.getObjectTypeById(object.typeId); onTransformEnd: () => void;
}
// Separate observer so only the 2 affected instances (selected/deselected)
// re-render on selection change, not all N objects in the scene.
const SelectionOverlay = observer(function ({ objectId, groupRef, onTransformEnd }: SelectionOverlayProps) {
const isSelected = state.worldEditor.isEnabled && const isSelected = state.worldEditor.isEnabled &&
state.worldEditor.selectedObjectId === object.id; state.worldEditor.selectedObjectId === objectId;
const selectionMode = isSelected ? state.worldEditor.selectedObjectMode : undefined; const selectionMode = isSelected ? state.worldEditor.selectedObjectMode : undefined;
useHelper(isSelected ? groupRef : { current: null } as any, BoxHelper, 'white'); useHelper(isSelected ? groupRef : { current: null } as any, BoxHelper, 'white');
if (!isSelected || selectionMode === undefined || !groupRef.current)
return null;
return (
<TransformControls
object={groupRef as RefObject<Group>}
mode={selectionMode}
onMouseUp={onTransformEnd}
/>
);
});
export const ObjectEditorView = observer(function ({ object }: ObjectEditorViewProps) {
const groupRef = useRef<Group>(null);
// Only observes world object types — not selection state — so won't
// re-render when a different object is selected.
const objectType = state.world.getObjectTypeById(object.typeId);
if (!objectType) if (!objectType)
return null; return null;
function handleClick(e: ThreeEvent<MouseEvent>) { function handleClick(e: ThreeEvent<MouseEvent>) {
if (e.delta > 5) return; if (e.delta > 5) return;
e.stopPropagation(); e.stopPropagation();
state.worldEditor.setSelectedObject(object.id, nextSelectionEditMode(selectionMode)); // Reading selection state inside an event handler: not tracked by observer.
const currentMode = state.worldEditor.isEnabled &&
state.worldEditor.selectedObjectId === object.id
? state.worldEditor.selectedObjectMode
: undefined;
state.worldEditor.setSelectedObject(object.id, nextSelectionEditMode(currentMode));
} }
function handleTransformEnd() { function handleTransformEnd() {
@ -45,13 +72,11 @@ export const ObjectEditorView = observer(function ({ object }: ObjectEditorViewP
} }
return (<> return (<>
{(isSelected && selectionMode !== undefined && groupRef.current) && <SelectionOverlay
<TransformControls objectId={object.id}
object={groupRef as RefObject<Group>} groupRef={groupRef}
mode={selectionMode} onTransformEnd={handleTransformEnd}
onMouseUp={handleTransformEnd} />
/>
}
<ObjectViewInternal <ObjectViewInternal
ref={groupRef} ref={groupRef}
object={object} object={object}

View File

@ -16,7 +16,7 @@ type ObjectViewInternalProps = {
onClick?: (e: ThreeEvent<MouseEvent>) => void; onClick?: (e: ThreeEvent<MouseEvent>) => void;
} }
export const ObjectViewInternal = observer(forwardRef<Group, ObjectViewInternalProps>( export const ObjectViewInternal = observer(forwardRef<Group | null, ObjectViewInternalProps>(
function ({ object, objectType, onClick }, ref) { function ({ object, objectType, onClick }, ref) {
const trimeshArgs = useMemo( const trimeshArgs = useMemo(
() => buildObjectTrimesh(objectType, state.world.data.voxelTypes), () => buildObjectTrimesh(objectType, state.world.data.voxelTypes),