This repository has been archived on 2020-09-30. You can view files and clone it, but cannot push or open issues or pull requests.
odyssey-old/Actors/Systems/Area/AreaProbe.gd
2020-07-20 15:04:56 +02:00

113 lines
3.5 KiB
GDScript

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()