feat: Add color variations for natural elements and dynamic water colors
This commit is contained in:
parent
a86acfff3a
commit
8ef18f52ab
@ -4,7 +4,7 @@ const PIXEL_SIZE = 4;
|
|||||||
const GRAVITY = 0.5;
|
const GRAVITY = 0.5;
|
||||||
const WATER_SPREAD = 3;
|
const WATER_SPREAD = 3;
|
||||||
|
|
||||||
// Colors
|
// Base Colors
|
||||||
const SAND_COLOR = '#e6c588';
|
const SAND_COLOR = '#e6c588';
|
||||||
const WATER_COLOR = '#4a80f5';
|
const WATER_COLOR = '#4a80f5';
|
||||||
const WALL_COLOR = '#888888';
|
const WALL_COLOR = '#888888';
|
||||||
@ -18,6 +18,30 @@ const LEAF_COLOR = '#228B22';
|
|||||||
const FIRE_COLORS = ['#FF0000', '#FF3300', '#FF6600', '#FF9900', '#FFCC00', '#FFFF00'];
|
const FIRE_COLORS = ['#FF0000', '#FF3300', '#FF6600', '#FF9900', '#FFCC00', '#FFFF00'];
|
||||||
const LAVA_COLORS = ['#FF0000', '#FF3300', '#FF4500', '#FF6600', '#FF8C00'];
|
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
|
// Element types
|
||||||
const EMPTY = 0;
|
const EMPTY = 0;
|
||||||
const SAND = 1;
|
const SAND = 1;
|
||||||
|
@ -22,19 +22,40 @@ function updateSand(x, y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateWater(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
|
// Try to move down
|
||||||
if (getPixel(x, y + 1) === EMPTY) {
|
if (getPixel(x, y + 1) === EMPTY) {
|
||||||
setPixel(x, y, EMPTY);
|
setPixel(x, y, EMPTY);
|
||||||
setPixel(x, y + 1, WATER);
|
setPixel(x, y + 1, WATER);
|
||||||
|
moveMetadata(x, y, x, y + 1);
|
||||||
}
|
}
|
||||||
// Try to move down-left or down-right
|
// Try to move down-left or down-right
|
||||||
else if (getPixel(x - 1, y + 1) === EMPTY) {
|
else if (getPixel(x - 1, y + 1) === EMPTY) {
|
||||||
setPixel(x, y, EMPTY);
|
setPixel(x, y, EMPTY);
|
||||||
setPixel(x - 1, y + 1, WATER);
|
setPixel(x - 1, y + 1, WATER);
|
||||||
|
moveMetadata(x, y, x - 1, y + 1);
|
||||||
}
|
}
|
||||||
else if (getPixel(x + 1, y + 1) === EMPTY) {
|
else if (getPixel(x + 1, y + 1) === EMPTY) {
|
||||||
setPixel(x, y, EMPTY);
|
setPixel(x, y, EMPTY);
|
||||||
setPixel(x + 1, y + 1, WATER);
|
setPixel(x + 1, y + 1, WATER);
|
||||||
|
moveMetadata(x, y, x + 1, y + 1);
|
||||||
}
|
}
|
||||||
// Try to spread horizontally
|
// Try to spread horizontally
|
||||||
else {
|
else {
|
||||||
|
@ -34,10 +34,16 @@ function growTree(x, y) {
|
|||||||
// Determine tree height (50-80 blocks, 10x bigger)
|
// Determine tree height (50-80 blocks, 10x bigger)
|
||||||
const treeHeight = 50 + Math.floor(Math.random() * 31);
|
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
|
// Grow the trunk upward
|
||||||
for (let i = 1; i < treeHeight; i++) {
|
for (let i = 1; i < treeHeight; i++) {
|
||||||
if (getPixel(x, y - i) === EMPTY) {
|
if (getPixel(x, y - i) === EMPTY) {
|
||||||
setPixel(x, y - i, WOOD);
|
setPixel(x, y - i, WOOD);
|
||||||
|
// Use the same wood color for the entire trunk
|
||||||
|
setMetadata(x, y - i, { colorIndex: woodColorIndex });
|
||||||
} else {
|
} else {
|
||||||
break; // Stop if we hit something
|
break; // Stop if we hit something
|
||||||
}
|
}
|
||||||
@ -85,6 +91,14 @@ function addBranches(x, y, treeHeight) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addLeaves(x, y, radius) {
|
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
|
// Add a cluster of leaves around the point
|
||||||
for (let dy = -radius; dy <= radius; dy++) {
|
for (let dy = -radius; dy <= radius; dy++) {
|
||||||
for (let dx = -radius; dx <= radius; dx++) {
|
for (let dx = -radius; dx <= radius; dx++) {
|
||||||
@ -100,6 +114,9 @@ function addLeaves(x, y, radius) {
|
|||||||
if (Math.random() < (1 - distance/radius/density)) {
|
if (Math.random() < (1 - distance/radius/density)) {
|
||||||
if (getPixel(x + dx, y + dy) === EMPTY) {
|
if (getPixel(x + dx, y + dy) === EMPTY) {
|
||||||
setPixel(x + dx, y + dy, LEAF);
|
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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
js/render.js
35
js/render.js
@ -47,21 +47,39 @@ function render() {
|
|||||||
if (type === SAND) {
|
if (type === SAND) {
|
||||||
ctx.fillStyle = SAND_COLOR;
|
ctx.fillStyle = SAND_COLOR;
|
||||||
} else if (type === WATER) {
|
} 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) {
|
} else if (type === WALL) {
|
||||||
ctx.fillStyle = WALL_COLOR;
|
ctx.fillStyle = WALL_COLOR;
|
||||||
} else if (type === DIRT) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} else if (type === SEED) {
|
||||||
ctx.fillStyle = SEED_COLOR;
|
ctx.fillStyle = SEED_COLOR;
|
||||||
} else if (type === GRASS_BLADE) {
|
} 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) {
|
} else if (type === FLOWER) {
|
||||||
// Get flower color from metadata or use a default
|
// Get flower color from metadata or use a default
|
||||||
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
||||||
@ -69,7 +87,10 @@ function render() {
|
|||||||
} else if (type === TREE_SEED) {
|
} else if (type === TREE_SEED) {
|
||||||
ctx.fillStyle = SEED_COLOR;
|
ctx.fillStyle = SEED_COLOR;
|
||||||
} else if (type === LEAF) {
|
} 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) {
|
} else if (type === FIRE) {
|
||||||
// Get fire color from metadata
|
// Get fire color from metadata
|
||||||
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
||||||
|
@ -83,14 +83,26 @@ function generateHills(chunkX, chunkY, chunkData, random) {
|
|||||||
// Top layer is grass
|
// Top layer is grass
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
chunkData[index] = GRASS;
|
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
|
// Next few layers are dirt
|
||||||
else if (depth < 5) {
|
else if (depth < 5) {
|
||||||
chunkData[index] = DIRT;
|
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
|
// Deeper layers are stone
|
||||||
else {
|
else {
|
||||||
chunkData[index] = STONE;
|
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) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
js/world.js
10
js/world.js
@ -62,6 +62,16 @@ function setPixel(worldX, worldY, type) {
|
|||||||
const index = localY * CHUNK_SIZE + localX;
|
const index = localY * CHUNK_SIZE + localX;
|
||||||
|
|
||||||
chunk[index] = type;
|
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) {
|
function getPixel(worldX, worldY) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user