feat: Enhance block appearance handling with detailed color and texture info, and improve block rendering performance
This commit is contained in:
@@ -18,7 +18,8 @@ function TurtleModel({ turtle, isSelected, onClick }) {
|
||||
if (!position) return null;
|
||||
|
||||
// Calculate rotation based on facing (0=North(-Z), 1=East(+X), 2=South(+Z), 3=West(-X))
|
||||
const rotation = facing !== undefined ? [0, (facing * Math.PI / 2), 0] : [0, 0, 0];
|
||||
// Add 180 degrees (Math.PI) to face the head forward initially, then apply facing rotation
|
||||
const rotation = facing !== undefined ? [0, (facing * Math.PI / 2) + Math.PI, 0] : [0, Math.PI, 0];
|
||||
|
||||
const color = mode === 'mining' ? '#4ade80' :
|
||||
mode === 'exploring' ? '#60a5fa' :
|
||||
@@ -134,69 +135,105 @@ function PathTrail({ turtle }) {
|
||||
);
|
||||
}
|
||||
|
||||
// Get color for block type
|
||||
function getBlockColor(blockName) {
|
||||
if (!blockName) return '#888';
|
||||
// Get color and texture info for block type
|
||||
function getBlockAppearance(blockName) {
|
||||
if (!blockName) return { color: '#888', pattern: 'solid' };
|
||||
|
||||
const name = blockName.toLowerCase();
|
||||
|
||||
// Ores
|
||||
if (name.includes('diamond')) return '#00ffff';
|
||||
if (name.includes('emerald')) return '#00ff00';
|
||||
if (name.includes('gold')) return '#ffd700';
|
||||
if (name.includes('iron')) return '#d4d4d4';
|
||||
if (name.includes('coal')) return '#1a1a1a';
|
||||
if (name.includes('redstone')) return '#ff0000';
|
||||
if (name.includes('lapis')) return '#0000ff';
|
||||
if (name.includes('copper')) return '#ff8c00';
|
||||
// Ores - bright colors with sparkle
|
||||
if (name.includes('diamond')) return { color: '#00ffff', pattern: 'ore', emissive: '#00ffff', intensity: 0.3 };
|
||||
if (name.includes('emerald')) return { color: '#00ff00', pattern: 'ore', emissive: '#00ff00', intensity: 0.3 };
|
||||
if (name.includes('gold')) return { color: '#ffd700', pattern: 'ore', emissive: '#ffd700', intensity: 0.2 };
|
||||
if (name.includes('iron')) return { color: '#d4d4d4', pattern: 'ore' };
|
||||
if (name.includes('coal')) return { color: '#1a1a1a', pattern: 'ore' };
|
||||
if (name.includes('redstone')) return { color: '#ff0000', pattern: 'ore', emissive: '#ff0000', intensity: 0.2 };
|
||||
if (name.includes('lapis')) return { color: '#1e40af', pattern: 'ore' };
|
||||
if (name.includes('copper')) return { color: '#ff8c00', pattern: 'ore' };
|
||||
|
||||
// Common blocks
|
||||
if (name.includes('stone')) return '#7f7f7f';
|
||||
if (name.includes('dirt')) return '#8b4513';
|
||||
if (name.includes('grass')) return '#228b22';
|
||||
if (name.includes('sand')) return '#f4a460';
|
||||
if (name.includes('gravel')) return '#808080';
|
||||
if (name.includes('bedrock')) return '#222';
|
||||
if (name.includes('obsidian')) return '#1a0033';
|
||||
if (name.includes('netherrack')) return '#8b0000';
|
||||
// Common blocks - textured
|
||||
if (name.includes('stone') && !name.includes('cobble')) return { color: '#7f7f7f', pattern: 'stone' };
|
||||
if (name.includes('cobblestone')) return { color: '#808080', pattern: 'cobble' };
|
||||
if (name.includes('dirt')) return { color: '#8b4513', pattern: 'dirt' };
|
||||
if (name.includes('grass')) return { color: '#228b22', pattern: 'grass' };
|
||||
if (name.includes('sand')) return { color: '#f4a460', pattern: 'sand' };
|
||||
if (name.includes('gravel')) return { color: '#808080', pattern: 'gravel' };
|
||||
if (name.includes('bedrock')) return { color: '#222', pattern: 'solid' };
|
||||
if (name.includes('obsidian')) return { color: '#1a0033', pattern: 'solid' };
|
||||
if (name.includes('netherrack')) return { color: '#8b0000', pattern: 'netherrack' };
|
||||
|
||||
return '#666666'; // Default
|
||||
return { color: '#666666', pattern: 'solid' };
|
||||
}
|
||||
|
||||
// WorldBlocks component to render discovered blocks
|
||||
function WorldBlocks({ blocks }) {
|
||||
const meshes = useMemo(() => {
|
||||
const instances = new Map();
|
||||
const [hoveredBlock, setHoveredBlock] = React.useState(null);
|
||||
|
||||
// Group blocks by appearance for better performance
|
||||
const blockGroups = useMemo(() => {
|
||||
const groups = new Map();
|
||||
|
||||
blocks.forEach(block => {
|
||||
const color = getBlockColor(block.name);
|
||||
if (!instances.has(color)) {
|
||||
instances.set(color, []);
|
||||
const appearance = getBlockAppearance(block.name);
|
||||
const key = `${appearance.color}-${appearance.pattern}`;
|
||||
|
||||
if (!groups.has(key)) {
|
||||
groups.set(key, { appearance, blocks: [] });
|
||||
}
|
||||
instances.get(color).push(block);
|
||||
groups.get(key).blocks.push(block);
|
||||
});
|
||||
|
||||
return instances;
|
||||
return Array.from(groups.values());
|
||||
}, [blocks]);
|
||||
|
||||
return (
|
||||
<group>
|
||||
{Array.from(meshes.entries()).map(([color, blockList]) => (
|
||||
<group key={color}>
|
||||
{blockList.map((block, idx) => (
|
||||
<mesh
|
||||
key={`${block.x},${block.y},${block.z}`}
|
||||
position={[block.x, block.y, block.z]}
|
||||
>
|
||||
<boxGeometry args={[0.9, 0.9, 0.9]} />
|
||||
<meshStandardMaterial
|
||||
color={color}
|
||||
transparent
|
||||
opacity={0.6}
|
||||
roughness={0.8}
|
||||
/>
|
||||
</mesh>
|
||||
))}
|
||||
{blockGroups.map((group, groupIdx) => (
|
||||
<group key={groupIdx}>
|
||||
{group.blocks.map((block) => {
|
||||
const appearance = group.appearance;
|
||||
const blockKey = `${block.x},${block.y},${block.z}`;
|
||||
const isHovered = hoveredBlock === blockKey;
|
||||
|
||||
return (
|
||||
<group key={blockKey}>
|
||||
<mesh
|
||||
position={[block.x, block.y, block.z]}
|
||||
onPointerOver={(e) => {
|
||||
e.stopPropagation();
|
||||
setHoveredBlock(blockKey);
|
||||
}}
|
||||
onPointerOut={() => setHoveredBlock(null)}
|
||||
>
|
||||
<boxGeometry args={[1.0, 1.0, 1.0]} />
|
||||
<meshStandardMaterial
|
||||
color={appearance.color}
|
||||
emissive={appearance.emissive || appearance.color}
|
||||
emissiveIntensity={isHovered ? (appearance.intensity || 0.05) + 0.3 : (appearance.intensity || 0.05)}
|
||||
roughness={appearance.pattern === 'ore' ? 0.4 : 0.8}
|
||||
metalness={appearance.pattern === 'ore' ? 0.3 : 0.0}
|
||||
transparent
|
||||
opacity={isHovered ? 0.95 : 0.85}
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
{/* Block label on hover */}
|
||||
{isHovered && (
|
||||
<Text
|
||||
position={[block.x, block.y + 0.8, block.z]}
|
||||
fontSize={0.3}
|
||||
color="white"
|
||||
anchorX="center"
|
||||
anchorY="middle"
|
||||
outlineWidth={0.05}
|
||||
outlineColor="#000000"
|
||||
>
|
||||
{block.name.replace('minecraft:', '').replace(/_/g, ' ').toUpperCase()}
|
||||
</Text>
|
||||
)}
|
||||
</group>
|
||||
);
|
||||
})}
|
||||
</group>
|
||||
))}
|
||||
</group>
|
||||
|
||||
Reference in New Issue
Block a user