Slay the Spire Style Map Generation in Godot 4
unknown
plain_text
2 years ago
2.8 kB
441
Indexable
################################################
# Map World
################################################
extends Node2D
@onready var map_node = preload("res://map_node.tscn")
@onready var map_nodes = $MapNodes
func _ready():
var map = MapGenerator.new().generate_map()
var map_height = map.size()
var map_width = map[0].size()
var floors = map
for y in map_height:
for x in map_width:
var n = map_node.instantiate()
n.room_data = floors[y][x]
map_nodes.add_child(n)
################################################
# Map Generator
################################################
extends Node
class_name MapGenerator
# https://kosgames.com/slay-the-spire-map-generation-guide-26769/
var distance_x = 60 # x distance between nodes
var distance_y = 50 # y distance between nodes
var wackiness = Vector2(25, 25) #a random factor so nodes aren't exactly lined up
var map_height = 15 # how many floors
var map_width = 7 # how many rooms on each floor
var total_paths = 6 # how many paths should generate
var floors = [] # this is the map layout!
func generate_map():
floors = []
# load an empty map
for y in map_height:
var room = []
room.resize(map_width)
room.fill(null)
floors.push_back(room)
for x in map_width:
var wack = Vector2(randf_range(0, wackiness.x), randf_range(0, wackiness.y))
floors[y][x] = {
"y": y,
"x": x,
"position": Vector2((x * distance_x) + wack.x , (y * distance_y) + wack.y),
"next_nodes": []
}
if y == map_height - 1:
floors[y][x].position.y = (y * distance_y) + distance_y
# load paths throughout the map
for i in _rand_starting_points():
var next_node = i
for y in map_height - 1:
next_node = _set_path(next_node, y)
# load boss room
for x in map_width:
if floors[map_height - 2][x].next_nodes.size():
floors[map_height - 2][x].next_nodes = [ Vector2(floor(map_width * 0.5), map_height - 1) ]
return floors
func _set_path(x, y):
var next_room_x
while next_room_x == null or _would_path_cross_existing_path(x, y, next_room_x):
next_room_x = clamp(randi_range(x - 1, x + 1), 0, map_width - 1)
floors[y][x].next_nodes.push_back(Vector2(next_room_x, y + 1))
return next_room_x
func _would_path_cross_existing_path(x, y, next_room_x):
var left_node
var right_node
if x > 0:
left_node = floors[y][x - 1]
if x < map_width - 1:
right_node = floors[y][x + 1]
if right_node and next_room_x > x:
for next in right_node.next_nodes:
if next.x < next_room_x:
return true
if left_node and next_room_x < x:
for next in left_node.next_nodes:
if next.x > next_room_x:
return true
return false
func _rand_starting_points():
var points = []
for i in total_paths:
points.push_back(randi_range(0, map_width - 1))
return points
Editor is loading...