diff --git a/js/constants.js b/js/constants.js index 01f5de9..c72ad61 100644 --- a/js/constants.js +++ b/js/constants.js @@ -4,7 +4,7 @@ const PIXEL_SIZE = 4; const GRAVITY = 0.5; const WATER_SPREAD = 3; -// Colors +// Base Colors const SAND_COLOR = '#e6c588'; const WATER_COLOR = '#4a80f5'; const WALL_COLOR = '#888888'; @@ -18,6 +18,30 @@ const LEAF_COLOR = '#228B22'; const FIRE_COLORS = ['#FF0000', '#FF3300', '#FF6600', '#FF9900', '#FFCC00', '#FFFF00']; const LAVA_COLORS = ['#FF0000', '#FF3300', '#FF4500', '#FF6600', '#FF8C00']; +// Color variation functions +function getRandomColorVariation(baseColor, range) { + // Convert hex to RGB + const r = parseInt(baseColor.slice(1, 3), 16); + const g = parseInt(baseColor.slice(3, 5), 16); + const b = parseInt(baseColor.slice(5, 7), 16); + + // Add random variation + const rVar = Math.max(0, Math.min(255, r + Math.floor(Math.random() * range * 2) - range)); + const gVar = Math.max(0, Math.min(255, g + Math.floor(Math.random() * range * 2) - range)); + const bVar = Math.max(0, Math.min(255, b + Math.floor(Math.random() * range * 2) - range)); + + // Convert back to hex + return `#${rVar.toString(16).padStart(2, '0')}${gVar.toString(16).padStart(2, '0')}${bVar.toString(16).padStart(2, '0')}`; +} + +// Generate color palettes for natural elements +const DIRT_COLORS = Array(10).fill().map(() => getRandomColorVariation(DIRT_COLOR, 15)); +const GRASS_COLORS = Array(10).fill().map(() => getRandomColorVariation(GRASS_COLOR, 20)); +const STONE_COLORS = Array(10).fill().map(() => getRandomColorVariation(STONE_COLOR, 15)); +const WOOD_COLORS = Array(10).fill().map(() => getRandomColorVariation(WOOD_COLOR, 15)); +const LEAF_COLORS = Array(10).fill().map(() => getRandomColorVariation(LEAF_COLOR, 25)); +const WATER_COLORS = Array(10).fill().map(() => getRandomColorVariation(WATER_COLOR, 20)); + // Element types const EMPTY = 0; const SAND = 1; diff --git a/js/elements/basic.js b/js/elements/basic.js index 748200b..7b0613e 100644 --- a/js/elements/basic.js +++ b/js/elements/basic.js @@ -22,19 +22,40 @@ function updateSand(x, y) { } function updateWater(x, y) { + // Update water color dynamically + const metadata = getMetadata(x, y); + if (metadata) { + if (metadata.waterColorTimer === undefined) { + metadata.waterColorTimer = 0; + } + + metadata.waterColorTimer++; + + // Change color occasionally + if (metadata.waterColorTimer > 20 && Math.random() < 0.1) { + metadata.colorIndex = Math.floor(Math.random() * 10); + metadata.waterColorTimer = 0; + } + + setMetadata(x, y, metadata); + } + // Try to move down if (getPixel(x, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x, y + 1, WATER); + moveMetadata(x, y, x, y + 1); } // Try to move down-left or down-right else if (getPixel(x - 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x - 1, y + 1, WATER); + moveMetadata(x, y, x - 1, y + 1); } else if (getPixel(x + 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y + 1, WATER); + moveMetadata(x, y, x + 1, y + 1); } // Try to spread horizontally else { diff --git a/js/elements/trees.js b/js/elements/trees.js index d5c9997..05bd891 100644 --- a/js/elements/trees.js +++ b/js/elements/trees.js @@ -34,10 +34,16 @@ function growTree(x, y) { // Determine tree height (50-80 blocks, 10x bigger) const treeHeight = 50 + Math.floor(Math.random() * 31); + // Generate consistent wood color for this tree + const woodColorIndex = Math.floor(Math.random() * 10); + setMetadata(x, y, { colorIndex: woodColorIndex }); + // Grow the trunk upward for (let i = 1; i < treeHeight; i++) { if (getPixel(x, y - i) === EMPTY) { setPixel(x, y - i, WOOD); + // Use the same wood color for the entire trunk + setMetadata(x, y - i, { colorIndex: woodColorIndex }); } else { break; // Stop if we hit something } @@ -85,6 +91,14 @@ function addBranches(x, y, treeHeight) { } function addLeaves(x, y, radius) { + // Generate a few leaf color variations for this tree + const baseLeafColorIndex = Math.floor(Math.random() * 10); + const leafColorIndices = [ + baseLeafColorIndex, + (baseLeafColorIndex + 1) % 10, + (baseLeafColorIndex + 2) % 10 + ]; + // Add a cluster of leaves around the point for (let dy = -radius; dy <= radius; dy++) { for (let dx = -radius; dx <= radius; dx++) { @@ -100,6 +114,9 @@ function addLeaves(x, y, radius) { if (Math.random() < (1 - distance/radius/density)) { if (getPixel(x + dx, y + dy) === EMPTY) { setPixel(x + dx, y + dy, LEAF); + // Assign one of the tree's leaf colors + const colorIndex = leafColorIndices[Math.floor(Math.random() * leafColorIndices.length)]; + setMetadata(x + dx, y + dy, { colorIndex }); } } } diff --git a/js/render.js b/js/render.js index 5040a7a..8dd8053 100644 --- a/js/render.js +++ b/js/render.js @@ -47,21 +47,39 @@ function render() { if (type === SAND) { ctx.fillStyle = SAND_COLOR; } else if (type === WATER) { - ctx.fillStyle = WATER_COLOR; + // Get water color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = WATER_COLORS[colorIndex]; } else if (type === WALL) { ctx.fillStyle = WALL_COLOR; } else if (type === DIRT) { - ctx.fillStyle = DIRT_COLOR; + // Get dirt color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = DIRT_COLORS[colorIndex]; } else if (type === STONE) { - ctx.fillStyle = STONE_COLOR; + // Get stone color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = STONE_COLORS[colorIndex]; } else if (type === GRASS) { - ctx.fillStyle = GRASS_COLOR; + // Get grass color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = GRASS_COLORS[colorIndex]; } else if (type === WOOD) { - ctx.fillStyle = WOOD_COLOR; + // Get wood color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = WOOD_COLORS[colorIndex]; } else if (type === SEED) { ctx.fillStyle = SEED_COLOR; } else if (type === GRASS_BLADE) { - ctx.fillStyle = GRASS_COLOR; + // Use the same color variation as grass + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = GRASS_COLORS[colorIndex]; } else if (type === FLOWER) { // Get flower color from metadata or use a default const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); @@ -69,7 +87,10 @@ function render() { } else if (type === TREE_SEED) { ctx.fillStyle = SEED_COLOR; } else if (type === LEAF) { - ctx.fillStyle = LEAF_COLOR; + // Get leaf color from metadata with variation + const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); + const colorIndex = metadata && metadata.colorIndex !== undefined ? metadata.colorIndex : 0; + ctx.fillStyle = LEAF_COLORS[colorIndex]; } else if (type === FIRE) { // Get fire color from metadata const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y); diff --git a/js/terrain.js b/js/terrain.js index ef9d4dd..a470f04 100644 --- a/js/terrain.js +++ b/js/terrain.js @@ -83,14 +83,26 @@ function generateHills(chunkX, chunkY, chunkData, random) { // Top layer is grass if (depth === 0) { chunkData[index] = GRASS; + // Set metadata with color index for grass + const worldX = chunkX * CHUNK_SIZE + x; + const worldY = chunkY * CHUNK_SIZE + y; + setMetadata(worldX, worldY, { colorIndex: Math.floor(Math.random() * 10) }); } // Next few layers are dirt else if (depth < 5) { chunkData[index] = DIRT; + // Set metadata with color index for dirt + const worldX = chunkX * CHUNK_SIZE + x; + const worldY = chunkY * CHUNK_SIZE + y; + setMetadata(worldX, worldY, { colorIndex: Math.floor(Math.random() * 10) }); } // Deeper layers are stone else { chunkData[index] = STONE; + // Set metadata with color index for stone + const worldX = chunkX * CHUNK_SIZE + x; + const worldY = chunkY * CHUNK_SIZE + y; + setMetadata(worldX, worldY, { colorIndex: Math.floor(Math.random() * 10) }); } } } diff --git a/js/world.js b/js/world.js index 6e6aa38..9167460 100644 --- a/js/world.js +++ b/js/world.js @@ -62,6 +62,16 @@ function setPixel(worldX, worldY, type) { const index = localY * CHUNK_SIZE + localX; chunk[index] = type; + + // Assign random color index for natural elements + if (type === DIRT || type === GRASS || type === STONE || type === WOOD || type === LEAF) { + const colorIndex = Math.floor(Math.random() * 10); + setMetadata(worldX, worldY, { ...getMetadata(worldX, worldY) || {}, colorIndex }); + } + else if (type === WATER) { + const colorIndex = Math.floor(Math.random() * 10); + setMetadata(worldX, worldY, { ...getMetadata(worldX, worldY) || {}, colorIndex, waterColorTimer: 0 }); + } } function getPixel(worldX, worldY) {