BSP
Binary Space Partitioning tree for procedural dungeon generation.
Overview
BSP recursively divides a rectangular region into smaller sub-regions, creating a tree structure perfect for generating dungeon rooms and corridors. Each leaf node represents a potential room, while the tree structure provides natural relationships for connecting them.
Quick Reference
# Create a BSP tree covering a dungeon area
bsp = mcrfpy.BSP(pos=(0, 0), size=(80, 50))
# Split recursively into rooms
bsp.split_recursive(depth=4, min_size=(8, 8))
# Iterate over leaf nodes (rooms)
for leaf in bsp:
print(f"Room at {leaf.pos}, size {leaf.size}")
# Create room in your grid...
# Use adjacency graph for corridor placement
for i, neighbors in enumerate(bsp.adjacency):
leaf = bsp.get_leaf(i)
for neighbor_idx in neighbors:
# leaf and bsp.get_leaf(neighbor_idx) share a wall
tiles = leaf.adjacent_tiles[neighbor_idx]
# tiles contains Vector coordinates for corridor placement
Constructor
mcrfpy.BSP(pos: tuple[int, int], size: tuple[int, int])
| Parameter |
Type |
Description |
pos |
tuple[int, int] |
Top-left position (x, y) of the root region |
size |
tuple[int, int] |
Width and height of the root region |
Properties
| Property |
Type |
Description |
pos |
tuple[int, int] |
Top-left position (x, y). Read-only. |
size |
tuple[int, int] |
Dimensions (width, height). Read-only. |
bounds |
tuple |
Combined position and size as ((x, y), (w, h)). Read-only. |
root |
BSPNode |
Reference to the root node. Read-only. |
adjacency |
BSPAdjacency |
Leaf adjacency graph. adjacency[i] returns tuple of neighbor indices. Read-only. |
Methods
| Method |
Description |
split_recursive(depth, min_size, max_ratio=1.5, seed=None) |
Recursively split to specified depth. Returns self. |
split_once(horizontal, position) |
Split root node once at specified position. Returns self. |
clear() |
Remove all children, keeping only root with original bounds. Returns self. |
leaves() |
Iterate all leaf nodes (rooms). Same as iterating BSP directly. |
traverse(order=Traversal.LEVEL_ORDER) |
Iterate all nodes in specified order. |
find(pos) |
Find smallest node containing position. Returns BSPNode or None. |
get_leaf(index) |
Get leaf node by index (0 to len(bsp)-1). |
to_heightmap(size=None, select='leaves', shrink=0, value=1.0) |
Convert to HeightMap with selected regions filled. |
BSPNode
BSPNode provides read-only access to individual nodes in the tree.
BSPNode Properties
| Property |
Type |
Description |
pos |
tuple[int, int] |
Top-left position (x, y) |
size |
tuple[int, int] |
Dimensions (width, height) |
bounds |
tuple |
Combined position and size |
level |
int |
Depth in tree (0 for root) |
is_leaf |
bool |
True if this node has no children |
split_horizontal |
bool or None |
Split orientation, None if leaf |
split_position |
int or None |
Split coordinate, None if leaf |
left |
BSPNode or None |
Left child, or None if leaf |
right |
BSPNode or None |
Right child, or None if leaf |
parent |
BSPNode or None |
Parent node, or None if root |
sibling |
BSPNode or None |
Other child of parent, or None |
leaf_index |
int or None |
Index in adjacency graph, None if not a leaf |
adjacent_tiles |
BSPAdjacentTiles |
Mapping of neighbor_index to wall tile coordinates |
BSPNode Methods
| Method |
Description |
contains(pos) |
Check if position is inside this node’s bounds |
center() |
Return the center point of this node’s bounds |
Iteration and Sequence Protocol
# len() returns number of leaf nodes
num_rooms = len(bsp)
# Iterate directly over leaves
for leaf in bsp:
pass
# Or use leaves() explicitly
for leaf in bsp.leaves():
pass
# Traverse all nodes (including internal)
for node in bsp.traverse(mcrfpy.Traversal.PRE_ORDER):
if node.is_leaf:
print("Leaf:", node.pos)
else:
print("Split at:", node.split_position)
Adjacency System
The adjacency system helps connect rooms with corridors:
# Get all neighbor relationships
for i, neighbors in enumerate(bsp.adjacency):
print(f"Leaf {i} is adjacent to: {neighbors}")
# Get wall tiles between adjacent leaves
leaf = bsp.get_leaf(0)
for neighbor_idx in leaf.adjacent_tiles.keys():
tiles = leaf.adjacent_tiles[neighbor_idx]
# tiles is a tuple of Vector objects representing
# coordinates on THIS leaf's edge that border the neighbor
for tile in tiles:
print(f"Wall tile at ({tile.x}, {tile.y})")
Important Notes
- BSPNode references become invalid after
clear() or split_recursive(). Re-fetch nodes from the BSP object after these operations.
- The adjacency graph is computed lazily and cached. It’s automatically invalidated when the tree structure changes.
- Maximum recursion depth is 16 to prevent memory exhaustion.