class_name MazeGenerator extends Node # Functions in this script generate mazes as PackedByteArrays. # Each bytes contains the present walls, using the enum below as mask. enum { MAZE_WALL_NORTH = 1, MAZE_WALL_WEST = 2, MAZE_WALL_SOUTH = 4, MAZE_WALL_EAST = 8 } enum { CNX_HORIZONTAL = 0, CNX_VERTICAL } # Generate a maze using Kruskal algorithm. Returns an array of bytes corresponding # to masks of present wall. func generate_kruskal(size : Vector2i, sd : int = -1) -> PackedByteArray: assert(size.x > 1 and size.y > 1) if sd >= 0: seed(sd) var count : int = size.x * size.y var maze : PackedByteArray = PackedByteArray() # The maze is initially composed of sealed rooms maze.resize(count); maze.fill(MAZE_WALL_NORTH + MAZE_WALL_WEST + MAZE_WALL_SOUTH + MAZE_WALL_EAST) # We start with a set per cell. They will be progressively merged until only one left var sets : PackedInt32Array = PackedInt32Array() sets.resize(count) var idx : int = 0 for y in range(size.y): for x in range(size.x): sets[idx] = idx idx += 1 # A connections is characterized by 4 parameters : x, y, horizontal/vertical, weight. # For convenience, we'll use a Vector4i var sorted_connections : Array[Vector4i] = [] # Horizontal connections is a (x-1) * y matrix for y in range(size.y): for x in range(size.x - 1): sorted_connections.append(Vector4i(x, y, CNX_HORIZONTAL, randi())) # Vertical connections is a x * (y-1) matrix. for y in range(size.y - 1): for x in range(size.x): sorted_connections.append(Vector4i(x, y, CNX_VERTICAL, randi())) # Sort the connections according to their weight sorted_connections.sort_custom(func(a : Vector4i, b : Vector4i) -> bool : return a.w > b.w) # For all connections, from least weight to the most while not sorted_connections.is_empty(): var c : Vector4i = sorted_connections.pop_back() var coord_a : Vector2i = Vector2i(c.x, c.y) var coord_b : Vector2i = Vector2i(c.x + 1, c.y) if c.z == CNX_HORIZONTAL else Vector2i(c.x, c.y + 1) var i_a : int = coord_a.x + coord_a.y * size.x; var i_b : int = coord_b.x + coord_b.y * size.x var set_a : int = sets[i_a]; var set_b : int = sets[i_b] if set_a == set_b: # the connection occurs in the same set, skip it continue # Depending on the nature of the connection, we remove walls from the adjacent cells if c.z == CNX_HORIZONTAL: maze[i_a] -= MAZE_WALL_EAST maze[i_b] -= MAZE_WALL_WEST else: maze[i_a] -= MAZE_WALL_SOUTH maze[i_b] -= MAZE_WALL_NORTH # Merge the two sets of cells var src_merge : int = max(set_a, set_b) var dst_merge : int = min(set_a, set_b) for i in range(count): if sets[i] == src_merge: sets[i] = dst_merge return maze
or share this direct link: