158 lines
5.1 KiB
Python
158 lines
5.1 KiB
Python
"""HeightMap Bezier Curves Demo
|
|
|
|
Demonstrates: dig_bezier for rivers, roads, and paths
|
|
Shows path carving with variable width and depth.
|
|
"""
|
|
import mcrfpy
|
|
from mcrfpy import automation
|
|
import math
|
|
|
|
GRID_WIDTH, GRID_HEIGHT = 64, 48
|
|
CELL_SIZE = 16
|
|
|
|
def terrain_with_water(h):
|
|
"""Terrain coloring with water in low areas."""
|
|
if h < 0.15:
|
|
# Water (carved paths)
|
|
t = h / 0.15
|
|
return mcrfpy.Color(int(30 + t * 30), int(60 + t * 50), int(140 + t * 40))
|
|
elif h < 0.25:
|
|
# Shore/wet ground
|
|
t = (h - 0.15) / 0.1
|
|
return mcrfpy.Color(int(80 + t * 40), int(100 + t * 30), int(80 - t * 20))
|
|
elif h < 0.5:
|
|
# Lowland
|
|
t = (h - 0.25) / 0.25
|
|
return mcrfpy.Color(int(70 + t * 20), int(130 + t * 20), int(50 + t * 10))
|
|
elif h < 0.7:
|
|
# Highland
|
|
t = (h - 0.5) / 0.2
|
|
return mcrfpy.Color(int(60 + t * 30), int(110 - t * 20), int(45 + t * 15))
|
|
elif h < 0.85:
|
|
# Hills
|
|
t = (h - 0.7) / 0.15
|
|
return mcrfpy.Color(int(100 + t * 30), int(95 + t * 25), int(70 + t * 30))
|
|
else:
|
|
# Peaks
|
|
t = (h - 0.85) / 0.15
|
|
return mcrfpy.Color(int(150 + t * 60), int(150 + t * 60), int(155 + t * 60))
|
|
|
|
def run_demo(runtime):
|
|
panel_w = GRID_WIDTH // 2
|
|
panel_h = GRID_HEIGHT
|
|
|
|
# Left panel: River system
|
|
river_map = mcrfpy.HeightMap((panel_w, panel_h), fill=0.5)
|
|
|
|
# Add terrain
|
|
noise = mcrfpy.NoiseSource(dimensions=2, algorithm='simplex', seed=42)
|
|
river_map.add_noise(noise, world_size=(10, 10), mode='fbm', octaves=4, scale=0.3)
|
|
river_map.add_hill((panel_w // 2, 5), 12, 0.3) # Mountain source
|
|
river_map.normalize(0.3, 0.9)
|
|
|
|
# Main river - wide, flowing from top to bottom
|
|
river_map.dig_bezier(
|
|
points=((panel_w // 2, 2), (panel_w // 4, 15), (panel_w * 3 // 4, 30), (panel_w // 2, panel_h - 3)),
|
|
start_radius=2, end_radius=5,
|
|
start_height=0.1, end_height=0.05
|
|
)
|
|
|
|
# Tributary from left
|
|
river_map.dig_bezier(
|
|
points=((3, 20), (10, 18), (15, 22), (panel_w // 3, 20)),
|
|
start_radius=1, end_radius=2,
|
|
start_height=0.12, end_height=0.1
|
|
)
|
|
|
|
# Tributary from right
|
|
river_map.dig_bezier(
|
|
points=((panel_w - 3, 15), (panel_w - 8, 20), (panel_w - 12, 18), (panel_w * 2 // 3, 25)),
|
|
start_radius=1, end_radius=2,
|
|
start_height=0.12, end_height=0.1
|
|
)
|
|
|
|
# Right panel: Road network
|
|
road_map = mcrfpy.HeightMap((panel_w, panel_h), fill=0.5)
|
|
road_map.add_noise(noise, world_size=(8, 8), mode='fbm', octaves=3, scale=0.2)
|
|
road_map.normalize(0.35, 0.7)
|
|
|
|
# Main road - relatively straight
|
|
road_map.dig_bezier(
|
|
points=((5, panel_h // 2), (15, panel_h // 2 - 3), (panel_w - 15, panel_h // 2 + 3), (panel_w - 5, panel_h // 2)),
|
|
start_radius=2, end_radius=2,
|
|
start_height=0.25, end_height=0.25
|
|
)
|
|
|
|
# North-south crossing road
|
|
road_map.dig_bezier(
|
|
points=((panel_w // 2, 5), (panel_w // 2 + 5, 15), (panel_w // 2 - 5, 35), (panel_w // 2, panel_h - 5)),
|
|
start_radius=2, end_radius=2,
|
|
start_height=0.25, end_height=0.25
|
|
)
|
|
|
|
# Winding mountain path
|
|
road_map.dig_bezier(
|
|
points=((5, 8), (15, 5), (20, 15), (25, 10)),
|
|
start_radius=1, end_radius=1,
|
|
start_height=0.28, end_height=0.28
|
|
)
|
|
|
|
# Curved path to settlement
|
|
road_map.dig_bezier(
|
|
points=((panel_w - 5, panel_h - 8), (panel_w - 15, panel_h - 5), (panel_w - 10, panel_h - 15), (panel_w // 2 + 5, panel_h - 10)),
|
|
start_radius=1, end_radius=2,
|
|
start_height=0.27, end_height=0.26
|
|
)
|
|
|
|
# Apply to grid
|
|
for y in range(panel_h):
|
|
for x in range(panel_w):
|
|
# Left panel: rivers
|
|
h = river_map.get((x, y))
|
|
color_layer.set(((x, y)), terrain_with_water(h))
|
|
|
|
# Right panel: roads (use brown for roads)
|
|
h2 = road_map.get((x, y))
|
|
if h2 < 0.3:
|
|
# Road surface
|
|
t = h2 / 0.3
|
|
color = mcrfpy.Color(int(140 - t * 40), int(120 - t * 30), int(80 - t * 20))
|
|
else:
|
|
color = terrain_with_water(h2)
|
|
color_layer.set(((panel_w + x, y)), color)
|
|
|
|
# Divider
|
|
for y in range(GRID_HEIGHT):
|
|
color_layer.set(((panel_w - 1, y)), mcrfpy.Color(100, 100, 100))
|
|
|
|
# Labels
|
|
labels = [("Rivers (dig_bezier)", 10, 10), ("Roads & Paths", panel_w * CELL_SIZE + 10, 10)]
|
|
for text, x, ypos in labels:
|
|
label = mcrfpy.Caption(text=text, pos=(x, ypos))
|
|
label.fill_color = mcrfpy.Color(255, 255, 255)
|
|
label.outline = 1
|
|
label.outline_color = mcrfpy.Color(0, 0, 0)
|
|
scene.children.append(label)
|
|
|
|
|
|
# Setup
|
|
scene = mcrfpy.Scene("bezier_demo")
|
|
|
|
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_07_heightmap_bezier.png")
|
|
print("Screenshot saved: procgen_07_heightmap_bezier.png")
|