tool extends Node2D class_name ProbeArea export(String) var area_name export(NodePath) var wall_tilemap export(NodePath) var base_tilemap var debug_font = preload("res://Graphics/UI/uifont.tres") const AREA_LAYER_ID = 16 onready var walls = get_node(wall_tilemap) as TileMap onready var base = get_node(base_tilemap) as TileMap onready var physics = get_world_2d().direct_space_state onready var map = walls.get_parent() as GameMap const TILE_SIZE = 32 var cells = {} var bounds = {} func _ready(): scout() update() func scout(): # Reset lists cells = {} bounds = {} # Get origin and immediate neighbour of probe var origin = Vector2(floor(position.x / TILE_SIZE), floor(position.y / TILE_SIZE)) cells[origin] = true var queue = get_neighbours(origin) # Use children probes for extra areas for child in get_children(): var child_origin = Vector2(floor((position.x + child.position.x) / TILE_SIZE), floor((position.y + child.position.y) / TILE_SIZE)) cells[child_origin] = true for neighbour in get_neighbours(child_origin): queue.push_front(neighbour) # Depth-first search while not queue.empty(): var current = queue.pop_front() # Have we checked this already? if not is_valid(current): continue var wall_tile = walls.get_cellv(current) if wall_tile == -1: var objects = physics.intersect_point(current * TILE_SIZE + Vector2.ONE * TILE_SIZE / 2.0, 1, [], AREA_LAYER_ID) if objects.size() > 0: bounds[current] = true else: cells[current] = true for neighbour in get_neighbours(current): queue.push_front(neighbour) else: bounds[current] = true # Join walls var joined = [] for cell in bounds: var sides = [ [Vector2(cell.x, cell.y-1),Vector2(cell.x, cell.y+1)], [Vector2(cell.x-1, cell.y),Vector2(cell.x+1, cell.y)], ] for side_pair in sides: if cells.has(side_pair[0]) and cells.has(side_pair[1]): # This bound is joined at one side, make it a cell and not a bound joined.push_back(cell) for wall in joined: bounds.erase(wall) cells[wall] = true func is_valid(cell: Vector2) -> bool: # Have we checked this already? if cells.has(cell) or bounds.has(cell): return false # Is it a valid tile for an area return base.get_cellv(cell) != -1 func get_neighbours(cell: Vector2) -> Array: var neighbours = [ Vector2(cell.x-1, cell.y-1), Vector2(cell.x, cell.y-1), Vector2(cell.x+1, cell.y-1), Vector2(cell.x-1, cell.y), Vector2(cell.x+1, cell.y), Vector2(cell.x-1, cell.y+1), Vector2(cell.x, cell.y+1), Vector2(cell.x+1, cell.y+1) ] var out = [] for neighbour in neighbours: # Have we checked this already? if not is_valid(neighbour): continue out.push_back(neighbour) return out func _draw(): if map == null or not map.debug_areas: return var origin = Vector2(floor(position.x / TILE_SIZE), floor(position.y / TILE_SIZE)) var draw_origin = origin * TILE_SIZE - position var rect_size = Vector2.ONE * TILE_SIZE draw_rect(Rect2(draw_origin, rect_size), Color.red, false, 2) draw_string(debug_font, Vector2.ZERO, area_name, Color.blue) for child in get_children(): var child_origin = Vector2(floor(child.position.x / TILE_SIZE), floor(child.position.y / TILE_SIZE)) draw_rect(Rect2(draw_origin + child_origin * TILE_SIZE, rect_size), Color.orange, false, 2) draw_string(debug_font, child.position, area_name + "/" + child.name, Color.blue) for wall in bounds: draw_rect(Rect2(wall * TILE_SIZE - position + Vector2.ONE * (TILE_SIZE / 2.0 - TILE_SIZE / 4.0), rect_size/2.0), Color(0,0.5,1,0.5)) func _area_moved(): scout() update() func serialize(): var subareas = {} for child in get_children(): subareas[child.name] = { "transform": child.transform } return { "name": area_name, "wall_path": wall_tilemap, "base_path": base_tilemap, "subareas": subareas } func deserialize(data): for subarea in data.subareas: var node = Node2D.new() node.name = subarea node.transform = data.subareas[subarea].transform add_child(node) area_name = data.name wall_tilemap = data.wall_path base_tilemap = data.base_path