@tool class_name Grid extends Node2D @export var cells: int: set(val): cells = val _calc_dims() @export var cell_size: int: set(val): cell_size = val _calc_dims() var total_width: int var total_height: int var thickness: int var off: Vector2 @onready var selection_manager: SelectionManager = Util.find(SelectionManager) func _enter_tree(): _calc_dims() func _ready(): _calc_dims() Engine.is_editor_hint() func _calc_dims(): total_width = cells * cell_size total_height = cells * cell_size thickness = 1 off = Vector2(total_width / -2, total_height / -2) func _process(_delta): queue_redraw() func _draw(): var r = Rect2(off, Vector2(total_width, total_height)) draw_rect(r, Color("222222"), true) var line_color = Color(1, 1, 1, 0.3) for i in range(cells + 1): draw_line(Vector2(i * cell_size, 0) + off, Vector2(i * cell_size, total_height) + off, line_color, thickness, false) for i in range(cells + 1): draw_line(Vector2(0, i * cell_size) + off, Vector2(total_width, i * cell_size) + off, line_color, thickness, false) for x in range(cells): for y in range(cells): var world_pos = Vector2i(x, y) var tile = _get_tile_at_tile_pos(world_pos) if tile == null: continue var t = Rect2( tile2world(world_pos), Vector2.ONE * cell_size ) draw_rect(t, Color("773322")) func tile2world(tile: Vector2i) -> Vector2i: return Vector2(tile) * cell_size + off func tile2world_rect(tile: Rect2i) -> Rect2: return Rect2(Vector2(tile.position) * cell_size + off, tile.size * cell_size) func tile2world_size(tile_size: Vector2i) -> Vector2: return Vector2(tile_size * cell_size) func world2tile(world_pos: Vector2) -> Vector2i: return Vector2i(((world_pos - off) / cell_size).floor()) func world2tile_f(world_pos: Vector2) -> Vector2: return (world_pos - off) / cell_size func world2tile_rect(rect: Rect2) -> Rect2i: var start = world2tile(rect.position) var end = world2tile(rect.end) return Rect2i(start, end - start) func quantize(world_position: Vector2, tile_size: Vector2i) -> Rect2: var q_pos = tile2world(world2tile(world_position)) return Rect2(q_pos, tile_size * cell_size) func quantize_on_objects(world_position: Vector2) -> Rect2: var tile_pos = world2tile(world_position) var size = Vector2i.ONE for tile in things: # we subtract ONE here, because the encloses thing is a >= test and goes OOB with integers if Rect2(tile.tile_pos, tile.size - Vector2i.ONE).encloses(Rect2(tile_pos, Vector2.ZERO)): size = tile.size tile_pos = tile.tile_pos break return tile2world_rect(Rect2i(tile_pos, size)) func _get_tile_at_tile_pos(pos: Vector2i) -> Positional: for tile in things: if tile.get_tilebox().has_point(pos): return tile return null func _get_tile_at_world_pos(pos: Vector2) -> Positional: #var world_pos = world2tile_f(pos) for tile in things: if tile.worldbox.has_point(pos): return tile return null func contains_world_pos(pos: Vector2) -> bool: var tile = world2tile(pos) if tile.x < 0 or tile.x > cells - 1: return false if tile.y < 0 or tile.y > cells - 1: return false return true func _shift_rect_half(rect: Rect2) -> Rect2: return Rect2(rect.position + rect.size / -2, rect.size) var left_dragging = false var left_mouse_down = false var left_mouse_down_start_pos: Vector2 = Vector2.ZERO func _is_mouse_pos_significant() -> bool: return (get_local_mouse_position() - left_mouse_down_start_pos).length_squared() > 50 func _input(event: InputEvent): if event is InputEventMouseMotion: if left_mouse_down: if not left_dragging and _is_mouse_pos_significant(): left_dragging = true _begin_drag(get_local_mouse_position()) elif left_dragging: _dragging(get_local_mouse_position()) elif event is InputEventMouseButton: if event.button_index == 1: left_mouse_down = event.pressed if event.pressed: left_mouse_down_start_pos = get_local_mouse_position() else: if left_dragging: left_dragging = false _end_drag(get_local_mouse_position()) else: _click(get_local_mouse_position()) var things: Array[Positional] = [] var things_dict: Dictionary = {} func register_tile(tile: Positional) -> void: things.append(tile) func remove_tile(tile: Positional) -> void: things.erase(tile) func _begin_drag(pos: Vector2): print("drag from", pos) func _dragging(pos: Vector2): pass func _end_drag(pos: Vector2): print("to", pos) func _click(pos: Vector2): print("click at", pos) var tile = _get_tile_at_world_pos(pos) if tile == null: selection_manager.clear() return selection_manager.select_array([tile]) func _double_click(pos: Vector2): pass func _right_click(pos: Vector2): pass