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
|
||||
function Scene() {
|
||||
function Scene({ interactionMode, onInteraction }) {
|
||||
const turtles = useTurtleStore((state) => state.getTurtleArray());
|
||||
const players = useTurtleStore((state) => Object.values(state.players || {}));
|
||||
const selectedTurtleId = useTurtleStore((state) => state.selectedTurtleId);
|
||||
|
||||
Reference in New Issue
Block a user