diff --git a/js/elements/fire.js b/js/elements/fire.js index 4f7caec..243f2e9 100644 --- a/js/elements/fire.js +++ b/js/elements/fire.js @@ -2,6 +2,7 @@ let fireUpdateCounter = 0; function updateFire(x, y) { + let modified = false; const metadata = getMetadata(x, y); if (!metadata) { @@ -10,15 +11,17 @@ function updateFire(x, y) { lifetime: 100 + Math.floor(Math.random() * 100), colorIndex: Math.floor(Math.random() * FIRE_COLORS.length) }); - return; + return true; } // Decrease lifetime metadata.lifetime--; + modified = true; // Randomly change color for flickering effect if (Math.random() < 0.2) { metadata.colorIndex = Math.floor(Math.random() * FIRE_COLORS.length); + modified = true; } // Update metadata @@ -29,7 +32,7 @@ function updateFire(x, y) { setPixel(x, y, EMPTY); setPixel(x, y - 1, FIRE); moveMetadata(x, y, x, y - 1); - return; + return true; } // Fire can also move slightly to the sides @@ -39,7 +42,7 @@ function updateFire(x, y) { setPixel(x, y, EMPTY); setPixel(x + direction, y - 1, FIRE); moveMetadata(x, y, x + direction, y - 1); - return; + return true; } } @@ -61,6 +64,7 @@ function updateFire(x, y) { lifetime: 100 + Math.floor(Math.random() * 100), colorIndex: Math.floor(Math.random() * FIRE_COLORS.length) }); + modified = true; } } @@ -68,10 +72,14 @@ function updateFire(x, y) { if (metadata.lifetime <= 0) { setPixel(x, y, EMPTY); removeMetadata(x, y); + return true; } + + return modified; } function updateLava(x, y) { + let modified = false; const metadata = getMetadata(x, y); if (!metadata) { @@ -79,11 +87,13 @@ function updateLava(x, y) { setMetadata(x, y, { colorIndex: Math.floor(Math.random() * LAVA_COLORS.length) }); + modified = true; } else { // Randomly change color for flowing effect if (Math.random() < 0.1) { metadata.colorIndex = Math.floor(Math.random() * LAVA_COLORS.length); setMetadata(x, y, metadata); + modified = true; } } @@ -94,17 +104,20 @@ function updateLava(x, y) { setPixel(x, y, EMPTY); setPixel(x, y + 1, LAVA); moveMetadata(x, y, x, y + 1); + return true; } // 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, LAVA); moveMetadata(x, y, x - 1, y + 1); + return true; } else if (getPixel(x + 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y + 1, LAVA); moveMetadata(x, y, x + 1, y + 1); + return true; } // Try to spread horizontally (slower than water) else if (Math.random() < 0.3) { @@ -115,20 +128,24 @@ function updateLava(x, y) { setPixel(x, y, EMPTY); setPixel(x - 1, y, LAVA); moveMetadata(x, y, x - 1, y); + return true; } else if (!goLeft && getPixel(x + 1, y) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y, LAVA); moveMetadata(x, y, x + 1, y); + return true; } // Try the other direction if first failed else if (!goLeft && getPixel(x - 1, y) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x - 1, y, LAVA); moveMetadata(x, y, x - 1, y); + return true; } else if (goLeft && getPixel(x + 1, y) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y, LAVA); moveMetadata(x, y, x + 1, y); + return true; } } } @@ -151,16 +168,21 @@ function updateLava(x, y) { lifetime: 100 + Math.floor(Math.random() * 100), colorIndex: Math.floor(Math.random() * FIRE_COLORS.length) }); + modified = true; } // Lava can melt sand into glass (stone) else if (nearbyType === SAND && Math.random() < 0.05) { setPixel(x + dir.dx, y + dir.dy, STONE); + modified = true; } // Lava can burn dirt else if (nearbyType === DIRT && Math.random() < 0.02) { setPixel(x + dir.dx, y + dir.dy, EMPTY); + modified = true; } } + + return modified; } diff --git a/js/elements/plants.js b/js/elements/plants.js index 85bfa3f..3ae81ed 100644 --- a/js/elements/plants.js +++ b/js/elements/plants.js @@ -4,18 +4,22 @@ function updateGrass(x, y) { if (getPixel(x, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x, y + 1, GRASS); + return true; } else if (getPixel(x - 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x - 1, y + 1, GRASS); + return true; } else if (getPixel(x + 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y + 1, GRASS); + return true; } else if (getPixel(x, y + 1) === WATER) { setPixel(x, y, WATER); setPixel(x, y + 1, GRASS); + return true; } // Grass can spread to nearby dirt @@ -28,13 +32,17 @@ function updateGrass(x, y) { const dir = directions[Math.floor(Math.random() * directions.length)]; if (getPixel(x + dir.dx, y + dir.dy) === DIRT) { setPixel(x + dir.dx, y + dir.dy, GRASS); + return true; } } // Grass dies if covered (no air above) if (getPixel(x, y - 1) !== EMPTY && Math.random() < 0.05) { setPixel(x, y, DIRT); + return true; } + + return false; } function updateSeed(x, y) { @@ -43,20 +51,24 @@ function updateSeed(x, y) { setPixel(x, y, EMPTY); setPixel(x, y + 1, SEED); moveMetadata(x, y, x, y + 1); + return true; } else if (getPixel(x - 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x - 1, y + 1, SEED); moveMetadata(x, y, x - 1, y + 1); + return true; } else if (getPixel(x + 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y + 1, SEED); moveMetadata(x, y, x + 1, y + 1); + return true; } // Seeds can float on water else if (getPixel(x, y + 1) === WATER) { // Just float, don't do anything + return false; } // If seed is on dirt or grass, it can germinate else if (getPixel(x, y + 1) === DIRT || getPixel(x, y + 1) === GRASS) { @@ -72,12 +84,16 @@ function updateSeed(x, y) { age: 0, height: 1 }); + return true; } else { // Regular seed becomes a grass blade setPixel(x, y, GRASS_BLADE); setMetadata(x, y, { age: 0, height: 1 }); + return true; } } + + return false; } function updateGrassBlade(x, y) { @@ -86,7 +102,7 @@ function updateGrassBlade(x, y) { if (!metadata) { setMetadata(x, y, { age: 0, height: 1 }); - return; + return true; } // Increment age @@ -99,13 +115,17 @@ function updateGrassBlade(x, y) { setMetadata(x, y - 1, { age: 0, height: metadata.height + 1 }); metadata.isTop = false; setMetadata(x, y, metadata); + return true; } // Grass blades die if covered by something other than another grass blade if (getPixel(x, y - 1) !== EMPTY && getPixel(x, y - 1) !== GRASS_BLADE && Math.random() < 0.01) { setPixel(x, y, EMPTY); removeMetadata(x, y); + return true; } + + return false; } function updateFlower(x, y) { @@ -119,7 +139,7 @@ function updateFlower(x, y) { age: 0, height: 1 }); - return; + return true; } // Increment age @@ -139,12 +159,14 @@ function updateFlower(x, y) { }); metadata.isTop = false; setMetadata(x, y, metadata); + return true; } // Flowers die if covered if (getPixel(x, y - 1) !== EMPTY && getPixel(x, y - 1) !== FLOWER && Math.random() < 0.01) { setPixel(x, y, EMPTY); removeMetadata(x, y); + return true; } // Flowers can drop seeds occasionally @@ -154,6 +176,9 @@ function updateFlower(x, y) { if (getPixel(x + dir, y) === EMPTY) { setPixel(x + dir, y, SEED); setMetadata(x + dir, y, { type: 'flower' }); + return true; } } + + return false; } diff --git a/js/elements/trees.js b/js/elements/trees.js index 05bd891..5004924 100644 --- a/js/elements/trees.js +++ b/js/elements/trees.js @@ -5,26 +5,33 @@ function updateTreeSeed(x, y) { setPixel(x, y, EMPTY); setPixel(x, y + 1, TREE_SEED); moveMetadata(x, y, x, y + 1); + return true; } else if (getPixel(x - 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x - 1, y + 1, TREE_SEED); moveMetadata(x, y, x - 1, y + 1); + return true; } else if (getPixel(x + 1, y + 1) === EMPTY) { setPixel(x, y, EMPTY); setPixel(x + 1, y + 1, TREE_SEED); moveMetadata(x, y, x + 1, y + 1); + return true; } // Seeds can float on water else if (getPixel(x, y + 1) === WATER) { // Just float, don't do anything + return false; } // If seed is on dirt or grass, it can grow into a tree else if (getPixel(x, y + 1) === DIRT || getPixel(x, y + 1) === GRASS) { // Start growing a tree growTree(x, y); + return true; } + + return false; } function growTree(x, y) { diff --git a/js/render.js b/js/render.js index 09ed541..2644ab4 100644 --- a/js/render.js +++ b/js/render.js @@ -13,6 +13,11 @@ function render() { const key = getChunkKey(chunkX, chunkY); + // Skip rendering if the chunk hasn't changed and isn't marked as dirty + if (!dirtyChunks.has(key) && !worldMoved) { + continue; + } + if (!chunks.has(key)) continue; const chunk = chunks.get(key); @@ -115,8 +120,14 @@ function render() { ); } } + + // Remove this chunk from the dirty list after rendering + dirtyChunks.delete(key); } + // Reset world moved flag after rendering + worldMoved = false; + // Draw cursor position and update debug info if (currentMouseX !== undefined && currentMouseY !== undefined) { const worldX = Math.floor(currentMouseX / PIXEL_SIZE) + worldOffsetX;