226 lines
7.1 KiB
JavaScript
226 lines
7.1 KiB
JavaScript
// TransitionSystem - Smooth transitions between biomes
|
|
class TransitionSystem {
|
|
constructor(scene, biomeSystem) {
|
|
this.scene = scene;
|
|
this.biomeSystem = biomeSystem;
|
|
|
|
// Transition settings
|
|
this.transitionWidth = 25; // Tiles for smooth transition
|
|
this.blendEnabled = true;
|
|
|
|
console.log('🌈 TransitionSystem initialized (width: ' + this.transitionWidth + ' tiles)');
|
|
}
|
|
|
|
// Check if tile is in transition zone
|
|
isInTransitionZone(x, y) {
|
|
const currentBiome = this.biomeSystem.getBiomeAt(x, y);
|
|
|
|
// Check nearby tiles for different biomes
|
|
const radius = Math.ceil(this.transitionWidth / 2);
|
|
|
|
for (let dy = -radius; dy <= radius; dy++) {
|
|
for (let dx = -radius; dx <= radius; dx++) {
|
|
if (dx === 0 && dy === 0) continue;
|
|
|
|
const checkX = x + dx;
|
|
const checkY = y + dy;
|
|
const checkBiome = this.biomeSystem.getBiomeAt(checkX, checkY);
|
|
|
|
if (checkBiome !== currentBiome) {
|
|
return true; // Different biome nearby!
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Get transition blend for a tile
|
|
getTransitionBlend(x, y) {
|
|
if (!this.blendEnabled) {
|
|
return {
|
|
primaryBiome: this.biomeSystem.getBiomeAt(x, y),
|
|
blendBiome: null,
|
|
blendFactor: 0
|
|
};
|
|
}
|
|
|
|
const currentBiome = this.biomeSystem.getBiomeAt(x, y);
|
|
|
|
// Find closest different biome
|
|
let closestBiome = null;
|
|
let closestDistance = Infinity;
|
|
|
|
const radius = this.transitionWidth;
|
|
|
|
for (let dy = -radius; dy <= radius; dy++) {
|
|
for (let dx = -radius; dx <= radius; dx++) {
|
|
if (dx === 0 && dy === 0) continue;
|
|
|
|
const checkX = x + dx;
|
|
const checkY = y + dy;
|
|
const checkBiome = this.biomeSystem.getBiomeAt(checkX, checkY);
|
|
|
|
if (checkBiome !== currentBiome) {
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
if (distance < closestDistance) {
|
|
closestDistance = distance;
|
|
closestBiome = checkBiome;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (closestBiome === null) {
|
|
// No transition
|
|
return {
|
|
primaryBiome: currentBiome,
|
|
blendBiome: null,
|
|
blendFactor: 0
|
|
};
|
|
}
|
|
|
|
// Calculate blend factor (0 = primary, 1 = blend)
|
|
const blendFactor = Math.max(0, 1 - (closestDistance / this.transitionWidth));
|
|
|
|
return {
|
|
primaryBiome: currentBiome,
|
|
blendBiome: closestBiome,
|
|
blendFactor: blendFactor
|
|
};
|
|
}
|
|
|
|
// Get blended tile color
|
|
getBlendedTileColor(x, y) {
|
|
const blend = this.getTransitionBlend(x, y);
|
|
|
|
if (blend.blendFactor === 0 || !blend.blendBiome) {
|
|
// No blending, return primary biome color
|
|
return this.getBiomeColor(blend.primaryBiome);
|
|
}
|
|
|
|
// Blend colors
|
|
const color1 = this.getBiomeColor(blend.primaryBiome);
|
|
const color2 = this.getBiomeColor(blend.blendBiome);
|
|
|
|
return this.blendColors(color1, color2, blend.blendFactor);
|
|
}
|
|
|
|
// Get biome base color
|
|
getBiomeColor(biomeId) {
|
|
const colors = {
|
|
'grassland': 0x3CB371, // Green
|
|
'forest': 0x2d5016, // Dark green
|
|
'desert': 0xd4c4a1, // Sand
|
|
'mountain': 0x808080, // Gray
|
|
'swamp': 0x3d5a3d // Murky green
|
|
};
|
|
|
|
return colors[biomeId] || 0x3CB371;
|
|
}
|
|
|
|
// Blend two colors
|
|
blendColors(color1, color2, factor) {
|
|
// Extract RGB components
|
|
const r1 = (color1 >> 16) & 0xFF;
|
|
const g1 = (color1 >> 8) & 0xFF;
|
|
const b1 = color1 & 0xFF;
|
|
|
|
const r2 = (color2 >> 16) & 0xFF;
|
|
const g2 = (color2 >> 8) & 0xFF;
|
|
const b2 = color2 & 0xFF;
|
|
|
|
// Blend
|
|
const r = Math.round(r1 * (1 - factor) + r2 * factor);
|
|
const g = Math.round(g1 * (1 - factor) + g2 * factor);
|
|
const b = Math.round(b1 * (1 - factor) + b2 * factor);
|
|
|
|
// Combine back to hex
|
|
return (r << 16) | (g << 8) | b;
|
|
}
|
|
|
|
// Get mixed features for transition zones
|
|
getMixedFeatures(x, y) {
|
|
const blend = this.getTransitionBlend(x, y);
|
|
|
|
if (blend.blendFactor === 0 || !blend.blendBiome) {
|
|
// No transition, use primary biome features only
|
|
return this.biomeSystem.applyBiomeFeatures(x, y);
|
|
}
|
|
|
|
// Get features from both biomes
|
|
const primaryFeatures = this.getBiomeFeatures(blend.primaryBiome, x, y);
|
|
const blendFeatures = this.getBiomeFeatures(blend.blendBiome, x, y);
|
|
|
|
// Mix based on blend factor
|
|
const mixedFeatures = [];
|
|
|
|
// Randomly choose which biome's features to use based on blend factor
|
|
if (Math.random() > blend.blendFactor) {
|
|
// Use primary biome features
|
|
if (primaryFeatures.length > 0 && Math.random() < 0.5) { // Reduce density in transitions
|
|
mixedFeatures.push(...primaryFeatures);
|
|
}
|
|
} else {
|
|
// Use blend biome features
|
|
if (blendFeatures.length > 0 && Math.random() < 0.5) {
|
|
mixedFeatures.push(...blendFeatures);
|
|
}
|
|
}
|
|
|
|
return mixedFeatures;
|
|
}
|
|
|
|
// Get features for a specific biome
|
|
getBiomeFeatures(biomeId, x, y) {
|
|
const features = [];
|
|
const biomeData = this.biomeSystem.biomes[biomeId];
|
|
|
|
if (!biomeData || !biomeData.features) return features;
|
|
|
|
// Check spawn probability for trees
|
|
if (biomeData.features.trees && Math.random() < biomeData.features.trees) {
|
|
features.push({ type: 'tree', size: 'medium' });
|
|
}
|
|
|
|
// Check spawn probability for rocks
|
|
if (biomeData.features.rocks && Math.random() < biomeData.features.rocks) {
|
|
features.push({ type: 'rock', size: 'small' });
|
|
}
|
|
|
|
// Desert-specific features
|
|
if (biomeData.features.cacti && Math.random() < biomeData.features.cacti) {
|
|
features.push({ type: 'cactus' });
|
|
}
|
|
|
|
// Mountain-specific features
|
|
if (biomeData.features.largeRocks && Math.random() < biomeData.features.largeRocks) {
|
|
features.push({ type: 'boulder' });
|
|
}
|
|
|
|
return features;
|
|
}
|
|
|
|
// Get statistics
|
|
getStats() {
|
|
return {
|
|
transitionWidth: this.transitionWidth,
|
|
blendEnabled: this.blendEnabled,
|
|
biomeCount: Object.keys(this.biomeSystem.biomes).length
|
|
};
|
|
}
|
|
|
|
// Enable/disable transitions
|
|
setBlendEnabled(enabled) {
|
|
this.blendEnabled = enabled;
|
|
console.log('🌈 Blend transitions: ' + (enabled ? 'ENABLED' : 'DISABLED'));
|
|
}
|
|
|
|
// Set transition width
|
|
setTransitionWidth(width) {
|
|
this.transitionWidth = Math.max(5, Math.min(50, width));
|
|
console.log('🌈 Transition width set to: ' + this.transitionWidth);
|
|
}
|
|
}
|