140 lines
4.8 KiB
Python
140 lines
4.8 KiB
Python
"""Advanced: Island Terrain Generation
|
|
|
|
Combines: Noise (base terrain) + Voronoi (biomes) + Hills + Erosion + Bezier (rivers)
|
|
Creates a tropical island with varied biomes and water features.
|
|
"""
|
|
import mcrfpy
|
|
from mcrfpy import automation
|
|
|
|
GRID_WIDTH, GRID_HEIGHT = 64, 48
|
|
CELL_SIZE = 16
|
|
|
|
def biome_color(elevation, moisture):
|
|
"""Determine color based on elevation and moisture."""
|
|
if elevation < 0.25:
|
|
# Water
|
|
t = elevation / 0.25
|
|
return mcrfpy.Color(int(30 + t * 30), int(80 + t * 40), int(160 + t * 40))
|
|
elif elevation < 0.32:
|
|
# Beach
|
|
return mcrfpy.Color(220, 200, 150)
|
|
elif elevation < 0.5:
|
|
# Lowland - varies by moisture
|
|
if moisture < 0.3:
|
|
return mcrfpy.Color(180, 170, 110) # Desert/savanna
|
|
elif moisture < 0.6:
|
|
return mcrfpy.Color(80, 140, 60) # Grassland
|
|
else:
|
|
return mcrfpy.Color(40, 100, 50) # Rainforest
|
|
elif elevation < 0.7:
|
|
# Highland
|
|
if moisture < 0.4:
|
|
return mcrfpy.Color(100, 90, 70) # Dry hills
|
|
else:
|
|
return mcrfpy.Color(50, 90, 45) # Forest
|
|
elif elevation < 0.85:
|
|
# Mountain
|
|
return mcrfpy.Color(110, 105, 100)
|
|
else:
|
|
# Peak
|
|
return mcrfpy.Color(220, 225, 230)
|
|
|
|
def run_demo(runtime):
|
|
# Step 1: Create base elevation using noise
|
|
noise = mcrfpy.NoiseSource(dimensions=2, algorithm='simplex', seed=42)
|
|
|
|
elevation = mcrfpy.HeightMap((GRID_WIDTH, GRID_HEIGHT), fill=0.0)
|
|
elevation.add_noise(noise, world_size=(12, 10), mode='fbm', octaves=5)
|
|
elevation.normalize(0.0, 1.0)
|
|
|
|
# Step 2: Create island shape using radial falloff
|
|
cx, cy = GRID_WIDTH / 2, GRID_HEIGHT / 2
|
|
max_dist = min(cx, cy) * 0.85
|
|
|
|
for y in range(GRID_HEIGHT):
|
|
for x in range(GRID_WIDTH):
|
|
dist = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5
|
|
falloff = max(0, 1 - (dist / max_dist) ** 1.5)
|
|
current = elevation.get((x, y))
|
|
elevation.fill(current * falloff, pos=(x, y), size=(1, 1))
|
|
|
|
# Step 3: Add central mountain range
|
|
elevation.add_hill((GRID_WIDTH // 2, GRID_HEIGHT // 2), 15, 0.5)
|
|
elevation.add_hill((GRID_WIDTH // 2 - 8, GRID_HEIGHT // 2 + 3), 8, 0.3)
|
|
elevation.add_hill((GRID_WIDTH // 2 + 10, GRID_HEIGHT // 2 - 5), 6, 0.25)
|
|
|
|
# Step 4: Create moisture map using different noise
|
|
moisture_noise = mcrfpy.NoiseSource(dimensions=2, algorithm='simplex', seed=123)
|
|
moisture = mcrfpy.HeightMap((GRID_WIDTH, GRID_HEIGHT), fill=0.0)
|
|
moisture.add_noise(moisture_noise, world_size=(8, 8), mode='fbm', octaves=3)
|
|
moisture.normalize(0.0, 1.0)
|
|
|
|
# Step 5: Add voronoi for biome boundaries
|
|
biome_regions = mcrfpy.HeightMap((GRID_WIDTH, GRID_HEIGHT), fill=0.0)
|
|
biome_regions.add_voronoi(num_points=8, coefficients=(0.5, -0.3), seed=77)
|
|
biome_regions.normalize(0.0, 1.0)
|
|
|
|
# Blend voronoi into moisture
|
|
moisture.lerp(biome_regions, 0.4)
|
|
|
|
# Step 6: Apply erosion to elevation
|
|
elevation.rain_erosion(drops=2000, erosion=0.08, sedimentation=0.04, seed=42)
|
|
elevation.normalize(0.0, 1.0)
|
|
|
|
# Step 7: Carve rivers from mountains to sea
|
|
# Main river
|
|
elevation.dig_bezier(
|
|
points=((GRID_WIDTH // 2, GRID_HEIGHT // 2 - 5),
|
|
(GRID_WIDTH // 2 - 10, GRID_HEIGHT // 2),
|
|
(GRID_WIDTH // 4, GRID_HEIGHT // 2 + 5),
|
|
(5, GRID_HEIGHT // 2 + 8)),
|
|
start_radius=0.5, end_radius=2,
|
|
start_height=0.3, end_height=0.15
|
|
)
|
|
|
|
# Secondary river
|
|
elevation.dig_bezier(
|
|
points=((GRID_WIDTH // 2 + 5, GRID_HEIGHT // 2),
|
|
(GRID_WIDTH // 2 + 15, GRID_HEIGHT // 3),
|
|
(GRID_WIDTH - 15, GRID_HEIGHT // 4),
|
|
(GRID_WIDTH - 5, GRID_HEIGHT // 4 + 3)),
|
|
start_radius=0.5, end_radius=1.5,
|
|
start_height=0.32, end_height=0.18
|
|
)
|
|
|
|
# Step 8: Render
|
|
for y in range(GRID_HEIGHT):
|
|
for x in range(GRID_WIDTH):
|
|
elev = elevation.get((x, y))
|
|
moist = moisture.get((x, y))
|
|
color_layer.set(((x, y)), biome_color(elev, moist))
|
|
|
|
# Title
|
|
title = mcrfpy.Caption(text="Island Terrain: Noise + Voronoi + Hills + Erosion + Rivers", pos=(10, 10))
|
|
title.fill_color = mcrfpy.Color(255, 255, 255)
|
|
title.outline = 1
|
|
title.outline_color = mcrfpy.Color(0, 0, 0)
|
|
scene.children.append(title)
|
|
|
|
|
|
# Setup
|
|
scene = mcrfpy.Scene("island")
|
|
|
|
grid = mcrfpy.Grid(
|
|
grid_size=(GRID_WIDTH, GRID_HEIGHT),
|
|
pos=(0, 0),
|
|
size=(GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE),
|
|
layers={}
|
|
)
|
|
grid.fill_color = mcrfpy.Color(0, 0, 0)
|
|
color_layer = grid.add_layer("color", z_index=-1)
|
|
scene.children.append(grid)
|
|
|
|
scene.activate()
|
|
|
|
# Run the demo
|
|
run_demo(0)
|
|
|
|
# Take screenshot
|
|
automation.screenshot("procgen_31_advanced_island.png")
|
|
print("Screenshot saved: procgen_31_advanced_island.png")
|