feat: Add lava element with dynamic colors and interactions
This commit is contained in:
parent
d6d874ab99
commit
c858da4c3e
@ -19,6 +19,7 @@
|
|||||||
<button id="seed-btn">Seed</button>
|
<button id="seed-btn">Seed</button>
|
||||||
<button id="tree-seed-btn">Tree Seed</button>
|
<button id="tree-seed-btn">Tree Seed</button>
|
||||||
<button id="fire-btn">Fire</button>
|
<button id="fire-btn">Fire</button>
|
||||||
|
<button id="lava-btn">Lava</button>
|
||||||
<button id="eraser-btn">Eraser</button>
|
<button id="eraser-btn">Eraser</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="navigation">
|
<div class="navigation">
|
||||||
|
116
script.js
116
script.js
@ -14,6 +14,7 @@ const SEED_COLOR = '#654321';
|
|||||||
const FLOWER_COLORS = ['#FF0000', '#FFFF00', '#FF00FF', '#FFA500', '#FFFFFF', '#00FFFF'];
|
const FLOWER_COLORS = ['#FF0000', '#FFFF00', '#FF00FF', '#FFA500', '#FFFFFF', '#00FFFF'];
|
||||||
const LEAF_COLOR = '#228B22';
|
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'];
|
||||||
|
|
||||||
// Element types
|
// Element types
|
||||||
const EMPTY = 0;
|
const EMPTY = 0;
|
||||||
@ -30,6 +31,7 @@ const FLOWER = 10;
|
|||||||
const TREE_SEED = 11;
|
const TREE_SEED = 11;
|
||||||
const LEAF = 12;
|
const LEAF = 12;
|
||||||
const FIRE = 13;
|
const FIRE = 13;
|
||||||
|
const LAVA = 14;
|
||||||
|
|
||||||
// Flammable materials
|
// Flammable materials
|
||||||
const FLAMMABLE_MATERIALS = [GRASS, WOOD, SEED, GRASS_BLADE, FLOWER, TREE_SEED, LEAF];
|
const FLAMMABLE_MATERIALS = [GRASS, WOOD, SEED, GRASS_BLADE, FLOWER, TREE_SEED, LEAF];
|
||||||
@ -71,6 +73,7 @@ window.onload = function() {
|
|||||||
document.getElementById('seed-btn').addEventListener('click', () => setTool(SEED));
|
document.getElementById('seed-btn').addEventListener('click', () => setTool(SEED));
|
||||||
document.getElementById('tree-seed-btn').addEventListener('click', () => setTool(TREE_SEED));
|
document.getElementById('tree-seed-btn').addEventListener('click', () => setTool(TREE_SEED));
|
||||||
document.getElementById('fire-btn').addEventListener('click', () => setTool(FIRE));
|
document.getElementById('fire-btn').addEventListener('click', () => setTool(FIRE));
|
||||||
|
document.getElementById('lava-btn').addEventListener('click', () => setTool(LAVA));
|
||||||
document.getElementById('eraser-btn').addEventListener('click', () => setTool(EMPTY));
|
document.getElementById('eraser-btn').addEventListener('click', () => setTool(EMPTY));
|
||||||
|
|
||||||
// Navigation controls
|
// Navigation controls
|
||||||
@ -125,6 +128,8 @@ function setTool(tool) {
|
|||||||
document.getElementById('tree-seed-btn').classList.add('active');
|
document.getElementById('tree-seed-btn').classList.add('active');
|
||||||
} else if (tool === FIRE) {
|
} else if (tool === FIRE) {
|
||||||
document.getElementById('fire-btn').classList.add('active');
|
document.getElementById('fire-btn').classList.add('active');
|
||||||
|
} else if (tool === LAVA) {
|
||||||
|
document.getElementById('lava-btn').classList.add('active');
|
||||||
} else if (tool === EMPTY) {
|
} else if (tool === EMPTY) {
|
||||||
document.getElementById('eraser-btn').classList.add('active');
|
document.getElementById('eraser-btn').classList.add('active');
|
||||||
}
|
}
|
||||||
@ -439,6 +444,8 @@ function updatePhysics() {
|
|||||||
updateTreeSeed(worldX, worldY);
|
updateTreeSeed(worldX, worldY);
|
||||||
} else if (type === FIRE) {
|
} else if (type === FIRE) {
|
||||||
updateFire(worldX, worldY);
|
updateFire(worldX, worldY);
|
||||||
|
} else if (type === LAVA) {
|
||||||
|
updateLava(worldX, worldY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -820,7 +827,7 @@ function updateWater(x, y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Water extinguishes fire
|
// Water extinguishes fire and turns lava into stone
|
||||||
const directions = [
|
const directions = [
|
||||||
{dx: -1, dy: 0}, {dx: 1, dy: 0},
|
{dx: -1, dy: 0}, {dx: 1, dy: 0},
|
||||||
{dx: 0, dy: -1}, {dx: 0, dy: 1},
|
{dx: 0, dy: -1}, {dx: 0, dy: 1},
|
||||||
@ -832,6 +839,13 @@ function updateWater(x, y) {
|
|||||||
if (getPixel(x + dir.dx, y + dir.dy) === FIRE) {
|
if (getPixel(x + dir.dx, y + dir.dy) === FIRE) {
|
||||||
setPixel(x + dir.dx, y + dir.dy, EMPTY);
|
setPixel(x + dir.dx, y + dir.dy, EMPTY);
|
||||||
removeMetadata(x + dir.dx, y + dir.dy);
|
removeMetadata(x + dir.dx, y + dir.dy);
|
||||||
|
} else if (getPixel(x + dir.dx, y + dir.dy) === LAVA) {
|
||||||
|
// Water turns lava into stone
|
||||||
|
setPixel(x + dir.dx, y + dir.dy, STONE);
|
||||||
|
removeMetadata(x + dir.dx, y + dir.dy);
|
||||||
|
// Water is consumed in the process
|
||||||
|
setPixel(x, y, EMPTY);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -907,6 +921,101 @@ function updateFire(x, y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add lava update function
|
||||||
|
function updateLava(x, y) {
|
||||||
|
const metadata = getMetadata(x, y);
|
||||||
|
|
||||||
|
if (!metadata) {
|
||||||
|
// Initialize metadata if it doesn't exist
|
||||||
|
setMetadata(x, y, {
|
||||||
|
colorIndex: Math.floor(Math.random() * LAVA_COLORS.length)
|
||||||
|
});
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lava moves slower than water
|
||||||
|
if (Math.random() < 0.7) {
|
||||||
|
// Try to move down
|
||||||
|
if (getPixel(x, y + 1) === EMPTY) {
|
||||||
|
setPixel(x, y, EMPTY);
|
||||||
|
setPixel(x, y + 1, LAVA);
|
||||||
|
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, LAVA);
|
||||||
|
moveMetadata(x, y, x - 1, y + 1);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
// Try to spread horizontally (slower than water)
|
||||||
|
else if (Math.random() < 0.3) {
|
||||||
|
// Randomly choose direction first
|
||||||
|
const goLeft = Math.random() > 0.5;
|
||||||
|
|
||||||
|
if (goLeft && getPixel(x - 1, y) === EMPTY) {
|
||||||
|
setPixel(x, y, EMPTY);
|
||||||
|
setPixel(x - 1, y, LAVA);
|
||||||
|
moveMetadata(x, y, x - 1, y);
|
||||||
|
} else if (!goLeft && getPixel(x + 1, y) === EMPTY) {
|
||||||
|
setPixel(x, y, EMPTY);
|
||||||
|
setPixel(x + 1, y, LAVA);
|
||||||
|
moveMetadata(x, y, x + 1, y);
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
} else if (goLeft && getPixel(x + 1, y) === EMPTY) {
|
||||||
|
setPixel(x, y, EMPTY);
|
||||||
|
setPixel(x + 1, y, LAVA);
|
||||||
|
moveMetadata(x, y, x + 1, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lava sets nearby flammable materials on fire
|
||||||
|
const directions = [
|
||||||
|
{dx: -1, dy: 0}, {dx: 1, dy: 0},
|
||||||
|
{dx: 0, dy: -1}, {dx: 0, dy: 1},
|
||||||
|
{dx: -1, dy: -1}, {dx: 1, dy: -1},
|
||||||
|
{dx: -1, dy: 1}, {dx: 1, dy: 1}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const dir of directions) {
|
||||||
|
const nearbyType = getPixel(x + dir.dx, y + dir.dy);
|
||||||
|
|
||||||
|
// Set flammable materials on fire
|
||||||
|
if (FLAMMABLE_MATERIALS.includes(nearbyType)) {
|
||||||
|
setPixel(x + dir.dx, y + dir.dy, FIRE);
|
||||||
|
setMetadata(x + dir.dx, y + dir.dy, {
|
||||||
|
lifetime: 100 + Math.floor(Math.random() * 100),
|
||||||
|
colorIndex: Math.floor(Math.random() * FIRE_COLORS.length)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lava can melt sand into glass (stone)
|
||||||
|
else if (nearbyType === SAND && Math.random() < 0.05) {
|
||||||
|
setPixel(x + dir.dx, y + dir.dy, STONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lava can burn dirt
|
||||||
|
else if (nearbyType === DIRT && Math.random() < 0.02) {
|
||||||
|
setPixel(x + dir.dx, y + dir.dy, EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getVisibleChunks() {
|
function getVisibleChunks() {
|
||||||
const visibleChunks = [];
|
const visibleChunks = [];
|
||||||
|
|
||||||
@ -1006,6 +1115,11 @@ function render() {
|
|||||||
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
||||||
const colorIndex = metadata ? metadata.colorIndex : 0;
|
const colorIndex = metadata ? metadata.colorIndex : 0;
|
||||||
ctx.fillStyle = FIRE_COLORS[colorIndex];
|
ctx.fillStyle = FIRE_COLORS[colorIndex];
|
||||||
|
} else if (type === LAVA) {
|
||||||
|
// Get lava color from metadata
|
||||||
|
const metadata = getMetadata(chunkX * CHUNK_SIZE + x, chunkY * CHUNK_SIZE + y);
|
||||||
|
const colorIndex = metadata ? metadata.colorIndex : 0;
|
||||||
|
ctx.fillStyle = LAVA_COLORS[colorIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the pixel
|
// Draw the pixel
|
||||||
|
Loading…
x
Reference in New Issue
Block a user