project/climate_zones_map.py

117 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
from opensimplex import OpenSimplex
from settings import WorldSettings
from numba import njit
class ClimateGenerator:
def __init__(self, height_map: np.ndarray, settings: WorldSettings):
self.height_map = height_map
self.settings = settings
self.noise = OpenSimplex(seed=settings.get_valid_seed())
# Палитра биомов
self.biome_colors = {
'water': (0.2, 0.4, 0.8, 1.0),
'ice': (0.95, 0.95, 0.98, 0.8),
'tundra': (0.4, 0.6, 0.9, 0.9),
'taiga': (0.1, 0.3, 0.15, 1.0),
'forest': (0.3, 0.6, 0.3, 1.0),
'desert': (0.9, 0.6, 0.2, 1.0),
'steppe': (0.8, 0.75, 0.5, 1.0),
'swamp': (0.4, 0.35, 0.2, 0.9),
'jungle': (0.1, 0.5, 0.1, 1.0),
'savanna': (0.8, 0.7, 0.3, 1.0)
}
def generate_biome_map(self, enabled_biomes=None) -> np.ndarray:
"""Генерация карты биомов с учетом выбранных биомов"""
if enabled_biomes is None:
enabled_biomes = list(self.biome_colors.keys())
height, width = self.height_map.shape
# Генерация шумов
temp_noise = self._generate_noise(width, height, 40)
moist_noise = self._generate_noise(width, height, 50)
biome_map = np.zeros((height, width, 4), dtype=np.float32)
self._fill_biome_map(
biome_map,
self.height_map,
temp_noise,
moist_noise,
enabled_biomes
)
return biome_map
def _generate_noise(self, width, height, scale):
"""Генерация многооктавного шума"""
noise = np.zeros((height, width))
for octave in [1.0, 0.5, 0.25]:
for y in range(height):
for x in range(width):
nx = x / (scale * octave)
ny = y / (scale * octave)
noise[y, x] += self.noise.noise2(nx, ny) * octave
return (noise - noise.min()) / (noise.max() - noise.min())
@staticmethod
@njit
def _fill_biome_map(biome_map, height_map, temp_noise, moist_noise, enabled_biomes):
height, width = height_map.shape
water_level = 0.05
for y in range(height):
latitude = abs(y/height - 0.5) * 2 # 0 на экваторе, 1 на полюсах
for x in range(width):
h = height_map[y,x]
# Вода (всегда включена, без прозрачности)
if h < water_level:
biome_map[y,x] = (0.2, 0.4, 0.8, 1.0)
continue
# Климатические параметры
temp = (0.7 - latitude * 0.5) * (1.0 - h * 0.5) * (0.8 + temp_noise[y,x] * 0.4)
moist = moist_noise[y,x]
# Расчёт прозрачности: сильнее зависит от высоты
alpha = 1.0 - h**2 * 0.7 # h^2 делает прозрачность резче на вершинах
# Выбор биома
if temp < 0.3: # Холодные зоны
if h > 0.8 and 'ice' in enabled_biomes:
biome = (0.95, 0.95, 0.98, alpha * 0.7) # Лёд прозрачнее
elif moist > 0.65 and 'tundra' in enabled_biomes:
biome = (0.4, 0.6, 0.9, alpha)
elif 'taiga' in enabled_biomes:
biome = (0.1, 0.3, 0.15, alpha)
else:
biome = (0.3, 0.6, 0.3, alpha)
elif temp < 0.6: # Умеренные зоны
if moist > 0.7 and 'swamp' in enabled_biomes:
biome = (0.4, 0.35, 0.2, alpha)
elif moist > 0.5 and 'forest' in enabled_biomes:
biome = (0.3, 0.6, 0.3, alpha)
elif moist > 0.3 and 'steppe' in enabled_biomes:
biome = (0.8, 0.75, 0.5, alpha)
elif 'desert' in enabled_biomes:
biome = (0.9, 0.6, 0.2, alpha)
else:
biome = (0.3, 0.6, 0.3, alpha)
else: # Теплые зоны
if moist < 0.3 and 'desert' in enabled_biomes:
biome = (0.9, 0.6, 0.2, alpha)
elif moist < 0.5 and 'savanna' in enabled_biomes:
biome = (0.8, 0.7, 0.3, alpha)
elif moist > 0.7 and 'jungle' in enabled_biomes:
biome = (0.1, 0.5, 0.1, alpha)
elif 'forest' in enabled_biomes:
biome = (0.3, 0.6, 0.3, alpha)
else:
biome = (0.8, 0.75, 0.5, alpha)
biome_map[y,x] = biome