217 lines
6.6 KiB
JavaScript
217 lines
6.6 KiB
JavaScript
// ChunkManager - Handles chunk-based terrain loading for large maps
|
|
class ChunkManager {
|
|
constructor(scene, chunkSize = 50) {
|
|
this.scene = scene;
|
|
this.chunkSize = chunkSize; // 50x50 tiles per chunk
|
|
this.biomeSystem = null; // Will be set by GameScene
|
|
|
|
// Active chunks (currently loaded)
|
|
this.activeChunks = new Map(); // Key: "chunkX,chunkY", Value: chunk data
|
|
|
|
// Chunk load radius (how many chunks around player)
|
|
this.loadRadius = 1; // Load 3x3 = 9 chunks at once
|
|
|
|
// Player position tracking
|
|
this.lastPlayerChunkX = -1;
|
|
this.lastPlayerChunkY = -1;
|
|
|
|
console.log(`💾 ChunkManager initialized (chunk size: ${chunkSize}x${chunkSize})`);
|
|
}
|
|
|
|
// Get chunk coordinates from world coordinates
|
|
worldToChunk(worldX, worldY) {
|
|
return {
|
|
chunkX: Math.floor(worldX / this.chunkSize),
|
|
chunkY: Math.floor(worldY / this.chunkSize)
|
|
};
|
|
}
|
|
|
|
// Get chunk key string
|
|
getChunkKey(chunkX, chunkY) {
|
|
return `${chunkX},${chunkY}`;
|
|
}
|
|
|
|
// Check if chunk is loaded
|
|
isChunkLoaded(chunkX, chunkY) {
|
|
return this.activeChunks.has(this.getChunkKey(chunkX, chunkY));
|
|
}
|
|
|
|
// Load a single chunk
|
|
loadChunk(chunkX, chunkY) {
|
|
const key = this.getChunkKey(chunkX, chunkY);
|
|
|
|
// Already loaded
|
|
if (this.activeChunks.has(key)) {
|
|
return this.activeChunks.get(key);
|
|
}
|
|
|
|
console.log(`📦 Loading chunk (${chunkX}, ${chunkY})`);
|
|
|
|
// Create chunk data
|
|
const chunk = {
|
|
chunkX,
|
|
chunkY,
|
|
key,
|
|
tiles: [],
|
|
objects: [], // Trees, rocks, decorations
|
|
sprites: [] // Phaser sprites for this chunk
|
|
};
|
|
|
|
// Generate or load chunk tiles
|
|
const startX = chunkX * this.chunkSize;
|
|
const startY = chunkY * this.chunkSize;
|
|
|
|
for (let y = 0; y < this.chunkSize; y++) {
|
|
for (let x = 0; x < this.chunkSize; x++) {
|
|
const worldX = startX + x;
|
|
const worldY = startY + y;
|
|
|
|
// Get biome for this tile
|
|
let biomeId = 'grassland';
|
|
if (this.biomeSystem) {
|
|
biomeId = this.biomeSystem.getBiomeAt(worldX, worldY);
|
|
}
|
|
|
|
chunk.tiles.push({
|
|
x: worldX,
|
|
y: worldY,
|
|
biome: biomeId
|
|
});
|
|
}
|
|
}
|
|
|
|
// Store chunk
|
|
this.activeChunks.set(key, chunk);
|
|
|
|
// Render chunk (if terrain system available)
|
|
if (this.scene.terrainSystem && this.scene.terrainSystem.renderChunk) {
|
|
this.scene.terrainSystem.renderChunk(chunk);
|
|
}
|
|
|
|
return chunk;
|
|
}
|
|
|
|
// Unload a single chunk
|
|
unloadChunk(chunkX, chunkY) {
|
|
const key = this.getChunkKey(chunkX, chunkY);
|
|
|
|
if (!this.activeChunks.has(key)) return;
|
|
|
|
console.log(`📤 Unloading chunk (${chunkX}, ${chunkY})`);
|
|
|
|
const chunk = this.activeChunks.get(key);
|
|
|
|
// Destroy all sprites in chunk
|
|
if (chunk.sprites) {
|
|
chunk.sprites.forEach(sprite => {
|
|
if (sprite && sprite.destroy) {
|
|
sprite.destroy();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Remove chunk
|
|
this.activeChunks.delete(key);
|
|
}
|
|
|
|
// Update active chunks based on player position
|
|
updateActiveChunks(playerX, playerY) {
|
|
const { chunkX, chunkY } = this.worldToChunk(playerX, playerY);
|
|
|
|
// Player hasn't changed chunks
|
|
if (chunkX === this.lastPlayerChunkX && chunkY === this.lastPlayerChunkY) {
|
|
return;
|
|
}
|
|
|
|
console.log(`🔄 Player moved to chunk (${chunkX}, ${chunkY})`);
|
|
|
|
this.lastPlayerChunkX = chunkX;
|
|
this.lastPlayerChunkY = chunkY;
|
|
|
|
// Determine which chunks should be loaded
|
|
const chunksToLoad = new Set();
|
|
|
|
for (let dy = -this.loadRadius; dy <= this.loadRadius; dy++) {
|
|
for (let dx = -this.loadRadius; dx <= this.loadRadius; dx++) {
|
|
const targetChunkX = chunkX + dx;
|
|
const targetChunkY = chunkY + dy;
|
|
chunksToLoad.add(this.getChunkKey(targetChunkX, targetChunkY));
|
|
}
|
|
}
|
|
|
|
// Unload chunks that are too far
|
|
const chunksToUnload = [];
|
|
for (const [key, chunk] of this.activeChunks) {
|
|
if (!chunksToLoad.has(key)) {
|
|
chunksToUnload.push({ x: chunk.chunkX, y: chunk.chunkY });
|
|
}
|
|
}
|
|
|
|
chunksToUnload.forEach(({ x, y }) => this.unloadChunk(x, y));
|
|
|
|
// Load new chunks
|
|
for (let dy = -this.loadRadius; dy <= this.loadRadius; dy++) {
|
|
for (let dx = -this.loadRadius; dx <= this.loadRadius; dx++) {
|
|
const targetChunkX = chunkX + dx;
|
|
const targetChunkY = chunkY + dy;
|
|
|
|
if (!this.isChunkLoaded(targetChunkX, targetChunkY)) {
|
|
this.loadChunk(targetChunkX, targetChunkY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Force reload all chunks (for debugging)
|
|
reloadAllChunks() {
|
|
console.log('🔄 Reloading all chunks...');
|
|
|
|
const chunksToReload = [];
|
|
for (const [key, chunk] of this.activeChunks) {
|
|
chunksToReload.push({ x: chunk.chunkX, y: chunk.chunkY });
|
|
}
|
|
|
|
// Unload all
|
|
chunksToReload.forEach(({ x, y }) => this.unloadChunk(x, y));
|
|
|
|
// Reload based on player position
|
|
if (this.scene.player) {
|
|
const pos = this.scene.player.getPosition();
|
|
this.updateActiveChunks(pos.x, pos.y);
|
|
}
|
|
}
|
|
|
|
// Get chunk at world position
|
|
getChunkAt(worldX, worldY) {
|
|
const { chunkX, chunkY } = this.worldToChunk(worldX, worldY);
|
|
return this.activeChunks.get(this.getChunkKey(chunkX, chunkY));
|
|
}
|
|
|
|
// Get statistics
|
|
getStats() {
|
|
return {
|
|
activeChunks: this.activeChunks.size,
|
|
chunkSize: this.chunkSize,
|
|
loadRadius: this.loadRadius,
|
|
maxChunks: Math.pow((this.loadRadius * 2 + 1), 2),
|
|
totalTilesLoaded: this.activeChunks.size * this.chunkSize * this.chunkSize
|
|
};
|
|
}
|
|
|
|
// Destroy all chunks
|
|
destroy() {
|
|
console.log('💾 ChunkManager destroying all chunks...');
|
|
|
|
for (const [key, chunk] of this.activeChunks) {
|
|
if (chunk.sprites) {
|
|
chunk.sprites.forEach(sprite => {
|
|
if (sprite && sprite.destroy) sprite.destroy();
|
|
});
|
|
}
|
|
}
|
|
|
|
this.activeChunks.clear();
|
|
console.log('💾 ChunkManager destroyed');
|
|
}
|
|
}
|