feat: Implement enhanced interaction handling with move, build, and selection previews in Map3D component
This commit is contained in:
@@ -1101,10 +1101,60 @@ function Scene({ interactionMode, onInteraction }) {
|
|||||||
const selectedTurtleId = useTurtleStore((state) => state.selectedTurtleId);
|
const selectedTurtleId = useTurtleStore((state) => state.selectedTurtleId);
|
||||||
const selectTurtle = useTurtleStore((state) => state.selectTurtle);
|
const selectTurtle = useTurtleStore((state) => state.selectTurtle);
|
||||||
const worldBlocks = useTurtleStore((state) => state.worldBlocks || []);
|
const worldBlocks = useTurtleStore((state) => state.worldBlocks || []);
|
||||||
|
const sendCommand = useTurtleStore((state) => state.sendCommand);
|
||||||
|
const setTurtleState = useTurtleStore((state) => state.setTurtleState);
|
||||||
|
|
||||||
// Mining areas state
|
// Mining areas state
|
||||||
const [miningAreas, setMiningAreas] = useState([]);
|
const [miningAreas, setMiningAreas] = useState([]);
|
||||||
const [selectedAreaId, setSelectedAreaId] = useState(null);
|
const [selectedAreaId, setSelectedAreaId] = useState(null);
|
||||||
|
|
||||||
|
// Interaction mode state
|
||||||
|
const [moveTarget, setMoveTarget] = useState(null);
|
||||||
|
const [buildPreview, setBuildPreview] = useState(null);
|
||||||
|
const [selectionStart, setSelectionStart] = useState(null);
|
||||||
|
const [selectionEnd, setSelectionEnd] = useState(null);
|
||||||
|
const controlsRef = useRef();
|
||||||
|
|
||||||
|
// Handle block clicks from interaction modes
|
||||||
|
const handleBlockClick = useCallback((event) => {
|
||||||
|
if (event.type === 'move' && selectedTurtleId) {
|
||||||
|
setMoveTarget(event.target);
|
||||||
|
// Send the turtle to the clicked position
|
||||||
|
setTurtleState(selectedTurtleId, 'moving', {
|
||||||
|
target: event.target
|
||||||
|
});
|
||||||
|
// Clear preview after a moment
|
||||||
|
setTimeout(() => setMoveTarget(null), 2000);
|
||||||
|
if (onInteraction) onInteraction({ mode: 'move', target: event.target, turtleId: selectedTurtleId });
|
||||||
|
} else if (event.type === 'build') {
|
||||||
|
setBuildPreview(event.target);
|
||||||
|
if (onInteraction) onInteraction({ mode: 'build', target: event.target });
|
||||||
|
} else if (event.type === 'select') {
|
||||||
|
if (!selectionStart) {
|
||||||
|
setSelectionStart(event.block);
|
||||||
|
setSelectionEnd(null);
|
||||||
|
} else {
|
||||||
|
setSelectionEnd(event.block);
|
||||||
|
if (onInteraction) onInteraction({
|
||||||
|
mode: 'select',
|
||||||
|
start: selectionStart,
|
||||||
|
end: event.block
|
||||||
|
});
|
||||||
|
// Reset after selection is complete
|
||||||
|
setTimeout(() => {
|
||||||
|
setSelectionStart(null);
|
||||||
|
setSelectionEnd(null);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedTurtleId, selectionStart, setTurtleState, onInteraction]);
|
||||||
|
|
||||||
|
// Disable orbit controls when in interactive mode
|
||||||
|
useEffect(() => {
|
||||||
|
if (controlsRef.current) {
|
||||||
|
controlsRef.current.enabled = interactionMode === INTERACTION_MODE.LOOK;
|
||||||
|
}
|
||||||
|
}, [interactionMode]);
|
||||||
|
|
||||||
// Load mining areas
|
// Load mining areas
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1170,8 +1220,20 @@ function Scene({ interactionMode, onInteraction }) {
|
|||||||
infiniteGrid
|
infiniteGrid
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Render discovered blocks */}
|
{/* Render discovered blocks with chunked rendering */}
|
||||||
<WorldBlocks blocks={worldBlocks} />
|
<WorldBlocks
|
||||||
|
blocks={worldBlocks}
|
||||||
|
interactionMode={interactionMode}
|
||||||
|
selectedTurtleId={selectedTurtleId}
|
||||||
|
onBlockClick={handleBlockClick}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Interaction mode previews */}
|
||||||
|
{moveTarget && <MoveTargetPreview position={moveTarget} />}
|
||||||
|
{buildPreview && <BuildPreview position={buildPreview} />}
|
||||||
|
{(selectionStart || selectionEnd) && (
|
||||||
|
<SelectionArea start={selectionStart} end={selectionEnd || selectionStart} />
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Mining areas */}
|
{/* Mining areas */}
|
||||||
{miningAreas.map((area) => {
|
{miningAreas.map((area) => {
|
||||||
@@ -1209,6 +1271,7 @@ function Scene({ interactionMode, onInteraction }) {
|
|||||||
|
|
||||||
{/* Camera controls */}
|
{/* Camera controls */}
|
||||||
<OrbitControls
|
<OrbitControls
|
||||||
|
ref={controlsRef}
|
||||||
target={centerPoint}
|
target={centerPoint}
|
||||||
enableDamping
|
enableDamping
|
||||||
dampingFactor={0.05}
|
dampingFactor={0.05}
|
||||||
|
|||||||
Reference in New Issue
Block a user