feat: Add move and build preview components with selection area for enhanced interaction
This commit is contained in:
@@ -983,8 +983,119 @@ function PlayerMarker({ player }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move target preview (ghost block showing where turtle will go)
|
||||||
|
function MoveTargetPreview({ position }) {
|
||||||
|
const meshRef = useRef();
|
||||||
|
|
||||||
|
useFrame((state) => {
|
||||||
|
if (meshRef.current) {
|
||||||
|
meshRef.current.position.y = position.y + Math.sin(state.clock.elapsedTime * 3) * 0.1;
|
||||||
|
meshRef.current.material.opacity = 0.3 + Math.sin(state.clock.elapsedTime * 2) * 0.15;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group>
|
||||||
|
<mesh ref={meshRef} position={[position.x, position.y, position.z]}>
|
||||||
|
<boxGeometry args={[0.8, 0.8, 0.8]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="#3b82f6"
|
||||||
|
transparent
|
||||||
|
opacity={0.4}
|
||||||
|
emissive="#3b82f6"
|
||||||
|
emissiveIntensity={0.5}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<Text
|
||||||
|
position={[position.x, position.y + 1.2, position.z]}
|
||||||
|
fontSize={0.3}
|
||||||
|
color="#3b82f6"
|
||||||
|
anchorX="center"
|
||||||
|
anchorY="middle"
|
||||||
|
outlineWidth={0.04}
|
||||||
|
outlineColor="#000000"
|
||||||
|
>
|
||||||
|
MOVE HERE
|
||||||
|
</Text>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build preview (ghost block showing where block will be placed)
|
||||||
|
function BuildPreview({ position }) {
|
||||||
|
const meshRef = useRef();
|
||||||
|
|
||||||
|
useFrame((state) => {
|
||||||
|
if (meshRef.current) {
|
||||||
|
meshRef.current.material.opacity = 0.3 + Math.sin(state.clock.elapsedTime * 2) * 0.15;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh ref={meshRef} position={[position.x, position.y, position.z]}>
|
||||||
|
<boxGeometry args={[1.0, 1.0, 1.0]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="#22c55e"
|
||||||
|
transparent
|
||||||
|
opacity={0.4}
|
||||||
|
emissive="#22c55e"
|
||||||
|
emissiveIntensity={0.5}
|
||||||
|
wireframe={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Area selection wireframe for SELECT mode
|
||||||
|
function SelectionArea({ start, end }) {
|
||||||
|
if (!start || !end) return null;
|
||||||
|
|
||||||
|
const minX = Math.min(start.x, end.x);
|
||||||
|
const minY = Math.min(start.y, end.y);
|
||||||
|
const minZ = Math.min(start.z, end.z);
|
||||||
|
const maxX = Math.max(start.x, end.x);
|
||||||
|
const maxY = Math.max(start.y, end.y);
|
||||||
|
const maxZ = Math.max(start.z, end.z);
|
||||||
|
|
||||||
|
const width = maxX - minX + 1;
|
||||||
|
const height = maxY - minY + 1;
|
||||||
|
const depth = maxZ - minZ + 1;
|
||||||
|
const centerX = (minX + maxX) / 2;
|
||||||
|
const centerY = (minY + maxY) / 2;
|
||||||
|
const centerZ = (minZ + maxZ) / 2;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group position={[centerX, centerY, centerZ]}>
|
||||||
|
<lineSegments>
|
||||||
|
<edgesGeometry args={[new THREE.BoxGeometry(width, height, depth)]} />
|
||||||
|
<lineBasicMaterial color="#f59e0b" linewidth={2} />
|
||||||
|
</lineSegments>
|
||||||
|
<mesh>
|
||||||
|
<boxGeometry args={[width, height, depth]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="#f59e0b"
|
||||||
|
transparent
|
||||||
|
opacity={0.1}
|
||||||
|
side={THREE.DoubleSide}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<Text
|
||||||
|
position={[0, height / 2 + 0.8, 0]}
|
||||||
|
fontSize={0.4}
|
||||||
|
color="#f59e0b"
|
||||||
|
anchorX="center"
|
||||||
|
anchorY="middle"
|
||||||
|
outlineWidth={0.04}
|
||||||
|
outlineColor="#000000"
|
||||||
|
>
|
||||||
|
{`${width}×${height}×${depth} Selection`}
|
||||||
|
</Text>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Main scene component
|
// Main scene component
|
||||||
function Scene() {
|
function Scene({ interactionMode, onInteraction }) {
|
||||||
const turtles = useTurtleStore((state) => state.getTurtleArray());
|
const turtles = useTurtleStore((state) => state.getTurtleArray());
|
||||||
const players = useTurtleStore((state) => Object.values(state.players || {}));
|
const players = useTurtleStore((state) => Object.values(state.players || {}));
|
||||||
const selectedTurtleId = useTurtleStore((state) => state.selectedTurtleId);
|
const selectedTurtleId = useTurtleStore((state) => state.selectedTurtleId);
|
||||||
|
|||||||
Reference in New Issue
Block a user