sandsim/js/elements/plants.js
Kacper Kostka (aider) a86acfff3a refactor: Spread game code into modular files for better maintainability
This commit reorganizes the game's source code into multiple files within a `js/` directory, creating a more modular and maintainable structure. The changes include:

- Created separate files for different game components:
  - `constants.js`: Game constants and element types
  - `world.js`: World management functions
  - `terrain.js`: Terrain generation logic
  - `physics.js`: Physics simulation
  - `render.js`: Rendering functions
  - `input.js`: Input handling
  - `main.js`: Main game initialization and loop
  - Element-specific files in `js/elements/`:
    - `basic.js`: Sand, water, dirt behaviors
    - `plants.js`: Grass, seeds, flowers
    - `trees.js`: Tree growth and leaf generation
    - `fire.js`: Fire and lava behaviors

- Updated `index.html` to load modules in the correct order
- Removed the monolithic `script.js`

The modular approach improves code readability, makes future extensions easier, and separates concerns more effectively.
2025-04-04 12:15:30 +02:00

160 lines
5.1 KiB
JavaScript

// Plant element behaviors (grass, seeds, trees)
function updateGrass(x, y) {
// Grass behaves like dirt for physics
if (getPixel(x, y + 1) === EMPTY) {
setPixel(x, y, EMPTY);
setPixel(x, y + 1, GRASS);
}
else if (getPixel(x - 1, y + 1) === EMPTY) {
setPixel(x, y, EMPTY);
setPixel(x - 1, y + 1, GRASS);
}
else if (getPixel(x + 1, y + 1) === EMPTY) {
setPixel(x, y, EMPTY);
setPixel(x + 1, y + 1, GRASS);
}
else if (getPixel(x, y + 1) === WATER) {
setPixel(x, y, WATER);
setPixel(x, y + 1, GRASS);
}
// Grass can spread to nearby dirt
if (Math.random() < 0.0005) {
const directions = [
{dx: -1, dy: 0}, {dx: 1, dy: 0},
{dx: 0, dy: -1}, {dx: 0, dy: 1}
];
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);
}
}
// Grass dies if covered (no air above)
if (getPixel(x, y - 1) !== EMPTY && Math.random() < 0.05) {
setPixel(x, y, DIRT);
}
}
function updateSeed(x, y) {
// Seeds fall like sand
if (getPixel(x, y + 1) === EMPTY) {
setPixel(x, y, EMPTY);
setPixel(x, y + 1, SEED);
moveMetadata(x, y, x, y + 1);
}
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);
}
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);
}
// Seeds can float on water
else if (getPixel(x, y + 1) === WATER) {
// Just float, don't do anything
}
// If seed is on dirt or grass, it can germinate
else if (getPixel(x, y + 1) === DIRT || getPixel(x, y + 1) === GRASS) {
const metadata = getMetadata(x, y);
// Check if this is a flower seed
if (metadata && metadata.type === 'flower') {
setPixel(x, y, FLOWER);
// Set a random flower color
setMetadata(x, y, {
type: 'flower',
color: FLOWER_COLORS[Math.floor(Math.random() * FLOWER_COLORS.length)],
age: 0,
height: 1
});
} else {
// Regular seed becomes a grass blade
setPixel(x, y, GRASS_BLADE);
setMetadata(x, y, { age: 0, height: 1 });
}
}
}
function updateGrassBlade(x, y) {
// Grass blades are static once grown
const metadata = getMetadata(x, y);
if (!metadata) {
setMetadata(x, y, { age: 0, height: 1 });
return;
}
// Increment age
metadata.age++;
setMetadata(x, y, metadata);
// Grass blades can grow taller up to a limit
if (metadata.age % 200 === 0 && metadata.height < 3 && getPixel(x, y - 1) === EMPTY) {
setPixel(x, y - 1, GRASS_BLADE);
setMetadata(x, y - 1, { age: 0, height: metadata.height + 1 });
metadata.isTop = false;
setMetadata(x, y, metadata);
}
// 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);
}
}
function updateFlower(x, y) {
// Flowers are similar to grass blades but with a colored top
const metadata = getMetadata(x, y);
if (!metadata) {
setMetadata(x, y, {
type: 'flower',
color: FLOWER_COLORS[Math.floor(Math.random() * FLOWER_COLORS.length)],
age: 0,
height: 1
});
return;
}
// Increment age
metadata.age++;
setMetadata(x, y, metadata);
// Flowers can grow taller up to a limit (2x bigger)
if (metadata.age % 300 === 0 && metadata.height < 8 && getPixel(x, y - 1) === EMPTY) {
// If this is the top of the flower, make it a stem and put a new flower on top
setPixel(x, y - 1, FLOWER);
setMetadata(x, y - 1, {
type: 'flower',
color: metadata.color,
age: 0,
height: metadata.height + 1,
isTop: true
});
metadata.isTop = false;
setMetadata(x, y, metadata);
}
// 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);
}
// Flowers can drop seeds occasionally
if (metadata.isTop && Math.random() < 0.0001) {
const directions = [-1, 1];
const dir = directions[Math.floor(Math.random() * directions.length)];
if (getPixel(x + dir, y) === EMPTY) {
setPixel(x + dir, y, SEED);
setMetadata(x + dir, y, { type: 'flower' });
}
}
}