Dijkstra to HeightMap Conversion

Convert pathfinding distance data into heightmaps for procedural generation, visualization, and gameplay mechanics.
Overview
A Dijkstra map stores the distance from every cell to a target point. Converting it to a HeightMap lets you use distance data for:
- Distance-based enemy difficulty scaling
- Fog/lighting intensity gradients
- Terrain generation based on paths
- Heat maps and influence visualization
Quick Start
import mcrfpy
scene = mcrfpy.Scene("quickstart")
mcrfpy.current_scene = scene
# Create a grid with walkable cells
grid = mcrfpy.Grid(grid_size=(20, 20))
for y in range(20):
for x in range(20):
grid.at((x, y)).walkable = True
scene.children.append(grid)
# Get dijkstra map from player position
dijkstra = grid.get_dijkstra_map((10, 10))
# Convert to heightmap
hmap = dijkstra.to_heightmap()
# Use the heights
player_distance = hmap[(5, 5)] # Distance from (5,5) to (10,10)
API Reference
Getting a Dijkstra Map
# From a grid, compute distances from a source point
dijkstra = grid.get_dijkstra_map((source_x, source_y))
# Query individual distances
distance = dijkstra.distance((x, y))
Converting to HeightMap
# Basic conversion - same size as dijkstra map
hmap = dijkstra.to_heightmap()
# Custom unreachable value (default is -1.0)
hmap = dijkstra.to_heightmap(unreachable=0.0)
hmap = dijkstra.to_heightmap(unreachable=999.0)
# Custom output size
hmap = dijkstra.to_heightmap(size=(width, height))
HeightMap Access
# Get height at position
height = hmap[(x, y)]
# HeightMaps also support standard operations
# (see HeightMap documentation for full API)
Common Patterns
Distance-Based Enemy Difficulty
Spawn harder enemies farther from the player’s starting position:
def spawn_enemies(grid, player_start, enemy_count):
"""Spawn enemies with difficulty based on distance from start."""
dijkstra = grid.get_dijkstra_map(player_start)
hmap = dijkstra.to_heightmap(unreachable=0.0)
enemies = []
spawn_points = find_valid_spawns(grid)
for point in spawn_points[:enemy_count]:
distance = hmap[point]
if distance < 5:
enemy_type = "rat" # Easy enemies near spawn
elif distance < 10:
enemy_type = "goblin" # Medium difficulty
elif distance < 15:
enemy_type = "orc" # Hard enemies
else:
enemy_type = "troll" # Boss-tier far from spawn
enemies.append(create_enemy(enemy_type, point))
return enemies
Distance-Based Fog Intensity
Create fog that’s thicker farther from the player:
def update_fog(grid, fog_layer, player_pos):
"""Update fog intensity based on distance from player."""
dijkstra = grid.get_dijkstra_map(player_pos)
hmap = dijkstra.to_heightmap(unreachable=20.0)
width, height = int(grid.grid_size[0]), int(grid.grid_size[1])
for y in range(height):
for x in range(width):
distance = hmap[(x, y)]
# Calculate fog alpha based on distance
if distance <= 3:
alpha = 0 # Clear near player
elif distance <= 8:
alpha = int((distance - 3) * 30) # Gradual fade
else:
alpha = 200 # Dense fog far away
fog_layer.set((x, y), mcrfpy.Color(20, 20, 40, alpha))
Visualizing Dijkstra as Color Gradient
Debug pathfinding by visualizing distances as colors:
def visualize_dijkstra(grid, color_layer, source):
"""Render dijkstra distances as a color gradient."""
dijkstra = grid.get_dijkstra_map(source)
hmap = dijkstra.to_heightmap(unreachable=-1.0)
width, height = int(grid.grid_size[0]), int(grid.grid_size[1])
# Find max distance for normalization
max_dist = 0
for y in range(height):
for x in range(width):
d = hmap[(x, y)]
if d > max_dist and d != -1.0:
max_dist = d
# Color each cell
for y in range(height):
for x in range(width):
dist = hmap[(x, y)]
if dist == -1.0:
# Unreachable - dark red
color = mcrfpy.Color(60, 0, 0)
elif dist == 0:
# Source - bright yellow
color = mcrfpy.Color(255, 255, 0)
else:
# Gradient from green (near) to blue (far)
t = dist / max_dist
r = 0
g = int(255 * (1 - t))
b = int(255 * t)
color = mcrfpy.Color(r, g, b)
color_layer.set((x, y), color)
River/Path Carving with Distance Fields
Use distance from multiple points to carve natural-looking paths:
def carve_river(grid, source, destination):
"""Carve a river-like path between two points."""
# Get distance from destination
dijkstra = grid.get_dijkstra_map(destination)
hmap = dijkstra.to_heightmap(unreachable=999.0)
# Start at source, follow decreasing distance
current = source
path = [current]
while current != destination:
x, y = current
best_neighbor = None
best_dist = hmap[current]
# Check all neighbors
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
if 0 <= nx < grid.grid_size[0] and 0 <= ny < grid.grid_size[1]:
neighbor_dist = hmap[(nx, ny)]
if neighbor_dist < best_dist:
best_dist = neighbor_dist
best_neighbor = (nx, ny)
if best_neighbor is None:
break # No path found
current = best_neighbor
path.append(current)
# Carve the path (make it water/floor)
# NOTE: GridPoint.tilesprite is legacy - write to a TileLayer instead,
# e.g. tile_layer.set(current, WATER_TILE)
grid.at(current).tilesprite = WATER_TILE
grid.at(current).walkable = True
return path
Influence Map for AI
Create an influence map showing areas controlled by different factions:
def create_influence_map(grid, player_pos, enemy_positions):
"""Create influence map for AI decision-making."""
width, height = int(grid.grid_size[0]), int(grid.grid_size[1])
# Player influence
player_dijkstra = grid.get_dijkstra_map(player_pos)
player_hmap = player_dijkstra.to_heightmap(unreachable=100.0)
# Combined enemy influence (take minimum distance to any enemy)
# Compute each enemy's heightmap once, outside the per-cell loop
# (recomputing it width*height times per enemy is wasteful).
enemy_hmaps = []
for enemy_pos in enemy_positions:
enemy_dijkstra = grid.get_dijkstra_map(enemy_pos)
enemy_hmaps.append(enemy_dijkstra.to_heightmap(unreachable=100.0))
influence = {}
for y in range(height):
for x in range(width):
player_dist = player_hmap[(x, y)]
# Find closest enemy
min_enemy_dist = 100.0
for enemy_hmap in enemy_hmaps:
enemy_dist = enemy_hmap[(x, y)]
min_enemy_dist = min(min_enemy_dist, enemy_dist)
# Influence: positive = player controlled, negative = enemy
influence[(x, y)] = min_enemy_dist - player_dist
return influence
Tip:
grid.get_dijkstra_map(root, roots=[...])also accepts multiple source points natively, which is the built-in way to get “distance to the closest enemy” instead of computing per-enemy maps and taking the minimum.
Performance Tips
- Cache dijkstra maps - Don’t recompute every frame if the grid hasn’t changed
- Use appropriate unreachable values - Choose values that make sense for your use case
- Consider size parameter - If you only need a portion, use custom size
- Batch operations - Convert once, query many times
Use Cases
| Use Case | Technique |
|---|---|
| Enemy difficulty scaling | Distance from spawn → enemy tier |
| Fog of war intensity | Distance from player → alpha value |
| Safe zone detection | Distance from hazards → safety score |
| Pathfinding visualization | Distance → color gradient |
| Terrain generation | Distance from features → elevation |
| AI influence maps | Compare distances from factions |
See Also
- Dijkstra Pathfinding - Basic dijkstra usage
- Fog of War - Visibility systems
- Dungeon Generator - Procedural generation