136 lines
4 KiB
GDScript
136 lines
4 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()
|
|
|
|
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
|