extends Node2D @export var map_width: int = 80 @export var map_height: int = 80 @export var tile_size: int = 64 var rng = RandomNumberGenerator.new() var zone_map = [] var region_map = [] var tile_map: TileMap const ZONE_ASPHALT = 0 const ZONE_CONCRETE = 1 const ZONE_GROUND = 2 const ZONE_GRASS = 3 const ZONE_STEEL = 4 const ZONE_WATER = 5 var zone_textures = {} func _ready() -> void: rng.randomize() tile_map = get_node("/root/Main/TileMap") if not tile_map: push_error("TileMap not found!") return load_textures() generate_map() func load_textures() -> void: var base = "res://assets/seamless/" var ts = TileSet.new() ts.tile_size = Vector2i(tile_size, tile_size) zone_textures = { ZONE_ASPHALT: ["asfalt1.jpg", "asfalt2.jpg", "asfalt3.jpg", "asfalt4.jpg", "asfalt5.jpg"], ZONE_CONCRETE: ["beton1.jpg", "beton2.jpg", "beton3.jpg", "beton4.jpg", "beton5.jpg"], ZONE_GROUND: ["ground1.jpg", "ground2.jpg", "ground3.jpg", "ground4.jpg", "ground5.jpg", "ground6.jpg", "ground7.jpg", "ground8.jpg", "ground9.jpg", "ground10.jpg"], ZONE_GRASS: ["grass1.jpg", "grass2.jpg", "grass3.jpg", "grass4.jpg", "grass5.jpg"], ZONE_STEEL: ["steel1.jpg", "steel2.jpg", "steel3.jpg", "steel4.jpg", "steel5.jpg"], } var source_id = 0 for zone in zone_textures: var textures = zone_textures[zone] var zone_sources = [] for tex_name in textures: var full_path = base + tex_name var tex = load(full_path) if tex: var source = TileSetAtlasSource.new() source.texture = tex source.texture_region_size = Vector2i(tile_size, tile_size) source.create_tile(Vector2i(0, 0)) ts.add_source(source, source_id) zone_sources.append(source_id) source_id += 1 zone_textures[zone] = zone_sources tile_map.tile_set = ts func generate_map() -> void: zone_map.clear() region_map.clear() for x in range(map_width): zone_map.append([]) region_map.append([]) for y in range(map_height): zone_map[x].append(-1) region_map[x].append(-1) generate_zones() add_water_features() smooth_zones() identify_regions() draw_map() func generate_zones() -> void: for x in range(map_width): for y in range(map_height): var h = get_noise(x, y) var zone = get_zone(h) zone_map[x][y] = zone func get_noise(x: int, y: int) -> float: var s = 0.05 var v = sin(x * s * 2) * cos(y * s * 1.5) v += sin(x * s * 4 + y * s * 3) * 0.3 v += sin(x * s * 8 + y * s * 7) * 0.15 return clamp(v * 0.5 + 0.5, 0.0, 1.0) func get_zone(val: float) -> int: if val < 0.15: return ZONE_ASPHALT elif val < 0.3: return ZONE_CONCRETE elif val < 0.45: return ZONE_STEEL elif val < 0.65: return ZONE_GROUND else: return ZONE_GRASS func add_water_features() -> void: for _i in range(8): var rx = rng.randi() % map_width var ry = rng.randi() % map_height create_water_body(rx, ry, rng.randi() % 3 + 1) func create_water_body(start_x: int, start_y: int, size: int) -> void: var queue = [{"x": start_x, "y": start_y}] var visited = {} visited[str(start_x) + "," + str(start_y)] = true var count = 0 while not queue.is_empty() and count < size * 15: var current = queue.pop_front() var x = current.x var y = current.y if x >= 0 and x < map_width and y >= 0 and y < map_height: if zone_map[x][y] != ZONE_WATER: zone_map[x][y] = ZONE_WATER count += 1 var dirs = [[0,1], [0,-1], [1,0], [-1,0]] for d in dirs: var nx = x + d[0] var ny = y + d[1] var key = str(nx) + "," + str(ny) if not visited.has(key): visited[key] = true if rng.randf() > 0.3: queue.append({"x": nx, "y": ny}) func smooth_zones() -> void: for iter in range(2): var new_zone = [] for x in range(map_width): new_zone.append([]) for y in range(map_height): new_zone[x].append(zone_map[x][y]) for x in range(1, map_width - 1): for y in range(1, map_height - 1): if zone_map[x][y] == ZONE_WATER: continue var counts = {} for dx in [-1, 0, 1]: for dy in [-1, 0, 1]: var n = zone_map[x + dx][y + dy] if n != ZONE_WATER: counts[n] = counts.get(n, 0) + 1 var max_count = 0 var dominant = zone_map[x][y] for z in counts: if counts[z] > max_count: max_count = counts[z] dominant = z if max_count >= 6: new_zone[x][y] = dominant zone_map = new_zone func identify_regions() -> void: var visited = {} var region_id = 0 for x in range(map_width): for y in range(map_height): var key = str(x) + "," + str(y) if visited.has(key): continue var zone = zone_map[x][y] var queue = [{"x": x, "y": y}] visited[key] = true while not queue.is_empty(): var current = queue.pop_front() var cx = current.x var cy = current.y region_map[cx][cy] = region_id var dirs = [[0,1], [0,-1], [1,0], [-1,0]] for d in dirs: var nx = cx + d[0] var ny = cy + d[1] var nkey = str(nx) + "," + str(ny) if nx >= 0 and nx < map_width and ny >= 0 and ny < map_height: if not visited.has(nkey) and zone_map[nx][ny] == zone: visited[nkey] = true queue.append({"x": nx, "y": ny}) region_id += 1 func draw_map() -> void: for x in range(map_width): for y in range(map_height): place_tile(x, y, zone_map[x][y], region_map[x][y]) func place_tile(x: int, y: int, zone: int, region: int) -> void: if not zone_textures.has(zone): zone = ZONE_GROUND var sources = zone_textures[zone] if sources.is_empty(): return var variant_idx = region % sources.size() var source_id = sources[variant_idx] tile_map.set_cell(0, Vector2i(x, y), source_id, Vector2i(0, 0))