perf: Optimize chunk rendering and generation by skipping off-screen chunks

This commit is contained in:
Kacper Kostka (aider) 2025-04-05 15:26:49 +02:00
parent c7735b8578
commit 4c96226d05

View File

@ -454,15 +454,35 @@ function moveMetadata(fromX, fromY, toX, toY) {
function getVisibleChunks() {
const visibleChunks = [];
// Calculate visible chunk range
// Calculate visible chunk range (chunks that might be visible on screen)
const startChunkX = Math.floor(worldOffsetX / CHUNK_SIZE) - 1;
const endChunkX = Math.ceil((worldOffsetX + canvas.width / PIXEL_SIZE) / CHUNK_SIZE) + 1;
const startChunkY = Math.floor(worldOffsetY / CHUNK_SIZE) - 1;
const endChunkY = Math.ceil((worldOffsetY + canvas.height / PIXEL_SIZE) / CHUNK_SIZE) + 1;
// Calculate the exact visible area in world coordinates
const visibleStartX = worldOffsetX;
const visibleEndX = worldOffsetX + canvas.width / PIXEL_SIZE;
const visibleStartY = worldOffsetY;
const visibleEndY = worldOffsetY + canvas.height / PIXEL_SIZE;
for (let chunkY = startChunkY; chunkY < endChunkY; chunkY++) {
for (let chunkX = startChunkX; chunkX < endChunkX; chunkX++) {
visibleChunks.push({ chunkX, chunkY });
// Calculate chunk boundaries in world coordinates
const chunkWorldStartX = chunkX * CHUNK_SIZE;
const chunkWorldEndX = (chunkX + 1) * CHUNK_SIZE;
const chunkWorldStartY = chunkY * CHUNK_SIZE;
const chunkWorldEndY = (chunkY + 1) * CHUNK_SIZE;
// Check if this chunk is actually visible in the viewport
const isVisible = !(
chunkWorldEndX < visibleStartX ||
chunkWorldStartX > visibleEndX ||
chunkWorldEndY < visibleStartY ||
chunkWorldStartY > visibleEndY
);
visibleChunks.push({ chunkX, chunkY, isVisible });
}
}
@ -474,19 +494,53 @@ function generateChunksAroundPlayer() {
const centerChunkY = Math.floor(worldOffsetY / CHUNK_SIZE);
const radius = 3; // Generate chunks within 3 chunks of the player
// Always generate the stone layer at y = 1
// Get visible chunks to prioritize their generation
const visibleChunks = getVisibleChunks();
const visibleChunkKeys = new Set(visibleChunks.map(chunk => getChunkKey(chunk.chunkX, chunk.chunkY)));
// Always generate the stone layer at y = 1 for visible chunks first
for (let dx = -radius; dx <= radius; dx++) {
const chunkX = centerChunkX + dx;
const chunkY = 1; // The chunk at y = 1 (moved from y = -1)
getOrCreateChunk(chunkX, chunkY);
const key = getChunkKey(chunkX, chunkY);
// Prioritize visible chunks
if (visibleChunkKeys.has(key)) {
getOrCreateChunk(chunkX, chunkY);
}
}
// Generate chunks in a square around the player
// Generate visible chunks first
for (const { chunkX, chunkY, isVisible } of visibleChunks) {
if (isVisible) {
getOrCreateChunk(chunkX, chunkY);
}
}
// Then generate non-visible chunks within the radius (with lower priority)
// Always generate the stone layer at y = 1 for remaining chunks
for (let dx = -radius; dx <= radius; dx++) {
const chunkX = centerChunkX + dx;
const chunkY = 1;
const key = getChunkKey(chunkX, chunkY);
// Skip if already generated
if (!visibleChunkKeys.has(key)) {
getOrCreateChunk(chunkX, chunkY);
}
}
// Generate remaining chunks in a square around the player
for (let dy = -radius; dy <= radius; dy++) {
for (let dx = -radius; dx <= radius; dx++) {
const chunkX = centerChunkX + dx;
const chunkY = centerChunkY + dy;
getOrCreateChunk(chunkX, chunkY);
const key = getChunkKey(chunkX, chunkY);
// Skip if already generated
if (!visibleChunkKeys.has(key)) {
getOrCreateChunk(chunkX, chunkY);
}
}
}
}