Generador de laberintos
Un laberinto perfecto excavado por backtracking. Los pasillos aparecen en el orden en que se abrieron, coloreados por ese orden.
El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.
Clases de Godot usadas
ImageImageTextureSprite2D
El código
scripts/main.gd
extends Node
const COLUMNS: int = 31
const ROWS: int = 17
const PER_FRAME: int = 10
const SEED: int = 20260814
const WALL: Color = Color('#2a2f3d')
const CARVED_START: Color = Color('#8da5f3')
const CARVED_END: Color = Color('#8eef97')
const DIRECTIONS: Array = [Vector2i.RIGHT, Vector2i.LEFT, Vector2i.DOWN, Vector2i.UP]
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
var steps: Array[Vector2i] = []
var revealed: int = 0
var image: Image
var texture: ImageTexture
func _ready() -> void:
_add_background()
rng.seed = SEED
image = Image.create(COLUMNS * 2 + 1, ROWS * 2 + 1, false, Image.FORMAT_RGBA8)
image.fill(WALL)
_carve()
texture = ImageTexture.create_from_image(image)
var view: Vector2 = get_viewport().get_visible_rect().size
var pixel: float = maxf(1.0, floorf(minf(view.x / image.get_width(), view.y / image.get_height())))
var maze: Sprite2D = Sprite2D.new()
maze.texture = texture
maze.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
maze.scale = Vector2(pixel, pixel)
maze.position = view * 0.5
add_child(maze)
print('a backtracker carves every cell exactly once, change SEED for another maze')
func _process(_delta: float) -> void:
if revealed >= steps.size():
return
var target: int = mini(revealed + PER_FRAME, steps.size())
while revealed < target:
image.set_pixelv(steps[revealed], CARVED_START.lerp(CARVED_END, float(revealed) / steps.size()))
revealed += 1
texture.update(image)
func _carve() -> void:
var visited: Dictionary = {Vector2i.ZERO: true}
var stack: Array[Vector2i] = [Vector2i.ZERO]
steps.append(_to_pixel(Vector2i.ZERO))
while not stack.is_empty():
var cell: Vector2i = stack[stack.size() - 1]
var options: Array[Vector2i] = []
for direction in DIRECTIONS:
var next: Vector2i = cell + direction
if next.x >= 0 and next.x < COLUMNS and next.y >= 0 and next.y < ROWS and not visited.has(next):
options.append(next)
if options.is_empty():
stack.pop_back()
continue
var chosen: Vector2i = options[rng.randi_range(0, options.size() - 1)]
visited[chosen] = true
steps.append(_to_pixel(cell) + chosen - cell)
steps.append(_to_pixel(chosen))
stack.append(chosen)
func _to_pixel(cell: Vector2i) -> Vector2i:
return cell * 2 + Vector2i.ONE
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)