feat: Add color variations for natural elements and dynamic water colors

This commit is contained in:
Kacper Kostka (aider) 2025-04-04 12:22:15 +02:00
parent a86acfff3a
commit 8ef18f52ab
6 changed files with 113 additions and 8 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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 });
}
}
}

View File

@ -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);

View File

@ -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) });
}
}
}

View File

@ -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) {