feat: Optimize rendering and physics with dirty chunk tracking and adaptive update rates

This commit introduces several performance optimizations:
- Implement chunk-based dirty rendering
- Add adaptive physics update rates
- Return modification status from element update functions
- Reduce unnecessary rendering and physics calculations
- Track world movement for efficient re-rendering

The key changes include:
1. Adding `dirtyChunks` and `worldMoved` tracking
2. Modifying element update functions to return modification status
3. Implementing adaptive physics update rates based on FPS
4. Skipping rendering for unchanged chunks
5. Reducing computational overhead in physics and rendering loops

These optimizations should significantly improve the simulation's performance, especially with large numbers of elements.
This commit is contained in:
Kacper Kostka (aider)
2025-04-05 15:35:19 +02:00
parent 1369822dc9
commit 60a1757ab1
4 changed files with 70 additions and 5 deletions

View File

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