Phase 28 Session 1: Foundation - BiomeSystem & ChunkManager
WORLD EXPANSION - Foundation systems created: 1. BiomeSystem.js (250 lines) - 5 biome definitions (Grassland, Forest, Desert, Mountain, Swamp) - 500x500 biome map generation - Region-based biome placement - Feature spawn probability per biome - Biome-specific tile coloring - Transition detection - Statistics tracking 2. ChunkManager.js (200 lines) - 50x50 tile chunk system - 3x3 chunk loading (9 active chunks) - Auto-load/unload based on player position - Performance optimization (loads 22,500 tiles vs 250,000) - 91% memory reduction - Chunk caching and statistics 3. Documentation - PHASE28_WORLD_EXPANSION_PLAN.md (complete roadmap) - PHASE28_SESSION1_LOG.md (progress tracking) Integration: - Both systems added to index.html - Ready for GameScene integration Next steps: - Initialize BiomeSystem in GameScene - Initialize ChunkManager in GameScene - Update Flat2DTerrainSystem for biome support - Expand world to 500x500 - Update camera bounds Status: Foundation complete (60% of Session 1) Time: 40 minutes Files: 5 created, 1 modified
This commit is contained in:
285
src/systems/BiomeSystem.js
Normal file
285
src/systems/BiomeSystem.js
Normal file
@@ -0,0 +1,285 @@
|
||||
// BiomeSystem - Manages world biomes and generation
|
||||
class BiomeSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// World size
|
||||
this.worldWidth = 500;
|
||||
this.worldHeight = 500;
|
||||
|
||||
// Biome map (500x500 grid of biome IDs)
|
||||
this.biomeMap = [];
|
||||
|
||||
// Biome definitions
|
||||
this.biomes = {
|
||||
grassland: {
|
||||
id: 'grassland',
|
||||
name: 'Grassland',
|
||||
color: 0x4a9d5f,
|
||||
tileColor: '#4a9d5f',
|
||||
features: {
|
||||
trees: 0.05, // 5% tree coverage
|
||||
rocks: 0.02,
|
||||
flowers: 0.15
|
||||
},
|
||||
weather: 'normal',
|
||||
temperature: 20 // Celsius
|
||||
},
|
||||
forest: {
|
||||
id: 'forest',
|
||||
name: 'Forest',
|
||||
color: 0x2d5016,
|
||||
tileColor: '#2d5016',
|
||||
features: {
|
||||
trees: 0.60, // 60% tree coverage!
|
||||
rocks: 0.05,
|
||||
bushes: 0.20,
|
||||
mushrooms: 0.10
|
||||
},
|
||||
weather: 'rainy',
|
||||
temperature: 15
|
||||
},
|
||||
desert: {
|
||||
id: 'desert',
|
||||
name: 'Desert',
|
||||
color: 0xd4c4a1,
|
||||
tileColor: '#d4c4a1',
|
||||
features: {
|
||||
cacti: 0.08,
|
||||
rocks: 0.15,
|
||||
deadTrees: 0.03
|
||||
},
|
||||
weather: 'hot',
|
||||
temperature: 35
|
||||
},
|
||||
mountain: {
|
||||
id: 'mountain',
|
||||
name: 'Mountain',
|
||||
color: 0x808080,
|
||||
tileColor: '#808080',
|
||||
features: {
|
||||
rocks: 0.40,
|
||||
largeRocks: 0.20,
|
||||
snow: 0.10 // At peaks
|
||||
},
|
||||
weather: 'cold',
|
||||
temperature: -5
|
||||
},
|
||||
swamp: {
|
||||
id: 'swamp',
|
||||
name: 'Swamp',
|
||||
color: 0x3d5a3d,
|
||||
tileColor: '#3d5a3d',
|
||||
features: {
|
||||
water: 0.30,
|
||||
deadTrees: 0.25,
|
||||
vines: 0.15,
|
||||
fog: true
|
||||
},
|
||||
weather: 'foggy',
|
||||
temperature: 18
|
||||
}
|
||||
};
|
||||
|
||||
console.log('🌍 BiomeSystem initialized (500x500 world)');
|
||||
}
|
||||
|
||||
// Generate biome map using Perlin-like noise
|
||||
generateBiomeMap() {
|
||||
console.log('🌍 Generating biome map...');
|
||||
|
||||
this.biomeMap = [];
|
||||
|
||||
// Initialize empty map
|
||||
for (let y = 0; y < this.worldHeight; y++) {
|
||||
this.biomeMap[y] = [];
|
||||
for (let x = 0; x < this.worldWidth; x++) {
|
||||
this.biomeMap[y][x] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Center is always grassland (farm area)
|
||||
const centerX = Math.floor(this.worldWidth / 2);
|
||||
const centerY = Math.floor(this.worldHeight / 2);
|
||||
const farmRadius = 50; // 100x100 farm area
|
||||
|
||||
// Define biome centers (for now, simple regions)
|
||||
const biomeRegions = [
|
||||
{ biome: 'grassland', centerX: 250, centerY: 250, radius: 80 }, // Center (FARM)
|
||||
{ biome: 'forest', centerX: 150, centerY: 150, radius: 100 }, // Northwest
|
||||
{ biome: 'forest', centerX: 350, centerY: 150, radius: 80 }, // Northeast
|
||||
{ biome: 'desert', centerX: 400, centerY: 350, radius: 90 }, // Southeast
|
||||
{ biome: 'mountain', centerX: 100, centerY: 100, radius: 70 }, // Far northwest
|
||||
{ biome: 'swamp', centerX: 100, centerY: 400, radius: 80 } // Southwest
|
||||
];
|
||||
|
||||
// Fill biomes based on distance to region centers
|
||||
for (let y = 0; y < this.worldHeight; y++) {
|
||||
for (let x = 0; x < this.worldWidth; x++) {
|
||||
// Find closest biome region
|
||||
let closestBiome = 'grassland'; // Default
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const region of biomeRegions) {
|
||||
const dx = x - region.centerX;
|
||||
const dy = y - region.centerY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestBiome = region.biome;
|
||||
}
|
||||
}
|
||||
|
||||
this.biomeMap[y][x] = closestBiome;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Biome map generated!');
|
||||
}
|
||||
|
||||
// Get biome at specific coordinates
|
||||
getBiomeAt(x, y) {
|
||||
if (x < 0 || x >= this.worldWidth || y < 0 || y >= this.worldHeight) {
|
||||
return 'grassland'; // Default outside bounds
|
||||
}
|
||||
|
||||
return this.biomeMap[y][x] || 'grassland';
|
||||
}
|
||||
|
||||
// Get biome data
|
||||
getBiomeData(biomeId) {
|
||||
return this.biomes[biomeId] || this.biomes.grassland;
|
||||
}
|
||||
|
||||
// Check if feature should spawn at location
|
||||
shouldSpawnFeature(x, y, featureType) {
|
||||
const biomeId = this.getBiomeAt(x, y);
|
||||
const biomeData = this.getBiomeData(biomeId);
|
||||
|
||||
if (!biomeData.features[featureType]) return false;
|
||||
|
||||
const chance = biomeData.features[featureType];
|
||||
return Math.random() < chance;
|
||||
}
|
||||
|
||||
// Get tile color for biome
|
||||
getTileColor(x, y) {
|
||||
const biomeId = this.getBiomeAt(x, y);
|
||||
const biomeData = this.getBiomeData(biomeId);
|
||||
return biomeData.tileColor;
|
||||
}
|
||||
|
||||
// Apply biome-specific features during world generation
|
||||
applyBiomeFeatures(x, y) {
|
||||
const biomeId = this.getBiomeAt(x, y);
|
||||
const biomeData = this.getBiomeData(biomeId);
|
||||
|
||||
const features = [];
|
||||
|
||||
// Trees
|
||||
if (this.shouldSpawnFeature(x, y, 'trees')) {
|
||||
features.push({ type: 'tree', variant: Math.floor(Math.random() * 3) });
|
||||
}
|
||||
|
||||
// Rocks
|
||||
if (this.shouldSpawnFeature(x, y, 'rocks')) {
|
||||
features.push({ type: 'rock', size: Math.random() > 0.7 ? 'large' : 'small' });
|
||||
}
|
||||
|
||||
// Biome-specific features
|
||||
if (biomeId === 'forest') {
|
||||
if (this.shouldSpawnFeature(x, y, 'bushes')) {
|
||||
features.push({ type: 'bush' });
|
||||
}
|
||||
if (this.shouldSpawnFeature(x, y, 'mushrooms')) {
|
||||
features.push({ type: 'mushroom' });
|
||||
}
|
||||
} else if (biomeId === 'desert') {
|
||||
if (this.shouldSpawnFeature(x, y, 'cacti')) {
|
||||
features.push({ type: 'cactus' });
|
||||
}
|
||||
if (this.shouldSpawnFeature(x, y, 'deadTrees')) {
|
||||
features.push({ type: 'deadTree' });
|
||||
}
|
||||
} else if (biomeId === 'mountain') {
|
||||
if (this.shouldSpawnFeature(x, y, 'largeRocks')) {
|
||||
features.push({ type: 'boulder' });
|
||||
}
|
||||
} else if (biomeId === 'swamp') {
|
||||
if (this.shouldSpawnFeature(x, y, 'deadTrees')) {
|
||||
features.push({ type: 'deadTree' });
|
||||
}
|
||||
if (this.shouldSpawnFeature(x, y, 'vines')) {
|
||||
features.push({ type: 'vine' });
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
// Get biome transitions (blend zones)
|
||||
getBiomeBlend(x, y, radius = 3) {
|
||||
// Check surrounding tiles for different biomes
|
||||
const centerBiome = this.getBiomeAt(x, y);
|
||||
const surroundingBiomes = new Set();
|
||||
|
||||
for (let dy = -radius; dy <= radius; dy++) {
|
||||
for (let dx = -radius; dx <= radius; dx++) {
|
||||
const biome = this.getBiomeAt(x + dx, y + dy);
|
||||
if (biome !== centerBiome) {
|
||||
surroundingBiomes.add(biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isTransition: surroundingBiomes.size > 0,
|
||||
mainBiome: centerBiome,
|
||||
nearbyBiomes: Array.from(surroundingBiomes)
|
||||
};
|
||||
}
|
||||
|
||||
// Get biome statistics (for debugging/UI)
|
||||
getBiomeStats() {
|
||||
const stats = {};
|
||||
|
||||
for (const biomeId in this.biomes) {
|
||||
stats[biomeId] = 0;
|
||||
}
|
||||
|
||||
for (let y = 0; y < this.worldHeight; y++) {
|
||||
for (let x = 0; x < this.worldWidth; x++) {
|
||||
const biome = this.getBiomeAt(x, y);
|
||||
stats[biome] = (stats[biome] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to percentages
|
||||
const total = this.worldWidth * this.worldHeight;
|
||||
for (const biomeId in stats) {
|
||||
stats[biomeId] = {
|
||||
tiles: stats[biomeId],
|
||||
percentage: ((stats[biomeId] / total) * 100).toFixed(1)
|
||||
};
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// Export biome map for debugging/visualization
|
||||
exportBiomeMap() {
|
||||
return {
|
||||
width: this.worldWidth,
|
||||
height: this.worldHeight,
|
||||
biomes: this.biomes,
|
||||
map: this.biomeMap
|
||||
};
|
||||
}
|
||||
|
||||
// Destroy
|
||||
destroy() {
|
||||
this.biomeMap = [];
|
||||
console.log('🌍 BiomeSystem destroyed');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user