extends Control onready var map_menu := ($menu/menubar/MapMenu as MenuButton).get_popup() onready var map_node := $map onready var cursor := $map/cursor onready var cursor_sprite := $map/cursor/preview const MAP_SCALE_MAX := 8.0 const MAP_SCALE_MIN := 0.25 const TileTabScene := preload("res://Scenes/Editor/TileTab.tscn") func _ready(): add_tile_tab("Base", $map/tiles/base) add_tile_tab("Floors", $map/tiles/floor) add_tile_tab("Walls", $map/tiles/walls) enum PlacingMode { NONE, TILEMAP, OBJECT } # Prevent input handler from running when other dialogs/actions are focused var input_lock := false # Drag variables var dragging := false var view_origin := Vector2.ZERO var mouse_origin := Vector2.ZERO # Placing variables var placing := false var deleting := false var placing_mode = PlacingMode.NONE var placing_layer = null var placing_tile_id := -1 var current_brush := "none" # Cursor variables var cursor_pos := Vector2.ZERO var pressed_pos := Vector2.ZERO const TILE_SIZE := 32 func _input(ev: InputEvent): if input_lock: return if ev is InputEventMouseMotion: if dragging: map_node.global_position = view_origin - (mouse_origin - ev.global_position) else: # Map cursor location to grid var tile_snap: Vector2 = map_node.scale * TILE_SIZE var mouse_offset: Vector2 = (ev.global_position - map_node.global_position) / tile_snap var new_cursor_pos := Vector2(floor(mouse_offset.x), floor(mouse_offset.y)) if new_cursor_pos != cursor_pos: var old_pos = cursor_pos cursor_pos = new_cursor_pos if placing or deleting: handle_held_cursor_move(old_pos, new_cursor_pos) cursor.position = cursor_pos * TILE_SIZE if ev is InputEventMouseButton: var mouse := ev as InputEventMouseButton if mouse.pressed: match ev.button_index: BUTTON_LEFT: if current_brush == "freehand": place_tiles([cursor_pos], placing_tile_id) placing = true pressed_pos = cursor_pos BUTTON_RIGHT: if current_brush == "freehand": place_tiles([cursor_pos], -1) deleting = true BUTTON_WHEEL_UP: # Zoom in var old_scale = map_node.scale if map_node.scale.x < MAP_SCALE_MAX: if map_node.scale.x < 1: map_node.scale *= 2 else: map_node.scale += Vector2.ONE map_node.position -= (map_node.position + mouse.position * map_node.scale)- (map_node.position + mouse.position * old_scale) BUTTON_WHEEL_DOWN: # Zoom out var old_scale = map_node.scale if map_node.scale.x > MAP_SCALE_MIN: if map_node.scale.x <= 1: map_node.scale /= 2 else: map_node.scale -= Vector2.ONE map_node.position -= (map_node.position + mouse.position * map_node.scale)- (map_node.position + mouse.position * old_scale) BUTTON_MIDDLE: view_origin = map_node.global_position mouse_origin = ev.global_position dragging = true else: match ev.button_index: BUTTON_LEFT: if current_brush == "rect": place_rect(pressed_pos, cursor_pos, placing_tile_id) placing = false BUTTON_RIGHT: deleting = false BUTTON_MIDDLE: dragging = false map_node.global_position = view_origin - (mouse_origin - ev.global_position) func handle_held_cursor_move(old_pos: Vector2, new_pos: Vector2): match current_brush: "freehand": var id = placing_tile_id # If deleting, null tile instead if deleting: id = -1 place_tiles([new_pos], id) func place_rect(a: Vector2, b: Vector2, id: int): if placing_layer == null: return var layer := placing_layer as TileMap # Sort coordinates var x_ord = Vector2(a.x, b.x) var y_ord = Vector2(a.y, b.y) if a.x > b.x: x_ord = Vector2(b.x, a.x) if a.y > b.y: y_ord = Vector2(b.y, a.y) var positions = [] for x in range(x_ord.x, x_ord.y+1): layer.set_cellv(Vector2(x, a.y), id) layer.set_cellv(Vector2(x, b.y), id) for y in range(y_ord.x, y_ord.y+1): layer.set_cellv(Vector2(a.x, y), id) layer.set_cellv(Vector2(b.x, y), id) layer.update_bitmask_region(a, b) func place_tiles(positions: Array, id: int): if placing_layer == null: return var layer := placing_layer as TileMap for pos in positions: # Place tile layer.set_cellv(pos, id) for pos in positions: # Update bitmask layer.update_bitmask_area(pos) var group := ButtonGroup.new() func add_tile_tab(name: String, tilemap: TileMap): var tab := add_tab(name) tab.connect("tile_selected", self, "_tile_selected", [name, tilemap]) var tileset := tilemap.tile_set var ids := tileset.get_tiles_ids() for id in ids: var tile_name := tileset.tile_get_name(id) var tile_icon := make_tile_texture(tileset, id) tab.add_entry(id, group, tile_icon) func add_tab(name: String) -> TileTab: var tab := TileTabScene.instance() as TileTab tab.name = name $layers/tabs.add_child(tab) return tab func _toggle_tile_input(enable: bool): input_lock = not enable func _tile_selected(id: int, name: String, tilemap: TileMap): cursor_sprite.texture = make_tile_texture(tilemap.tile_set, id) placing_mode = PlacingMode.TILEMAP placing_layer = tilemap placing_tile_id = id func make_tile_texture(tileset: TileSet, id: int) -> AtlasTexture: var tile_mode := tileset.tile_get_tile_mode(id) var tile_icon := AtlasTexture.new() tile_icon.atlas = tileset.tile_get_texture(id) match tile_mode: TileSet.AUTO_TILE: var tile_size := tileset.autotile_get_size(id) tile_icon.region = Rect2( tileset.autotile_get_icon_coordinate(id) * tile_size, tile_size ) TileSet.SINGLE_TILE: tile_icon.region = tileset.tile_get_region(id) return tile_icon onready var layers_panel = $layers onready var brush_panel = $tools/brushPanel func _tool_selected(tool_type): layers_panel.visible = false brush_panel.visible = false placing_mode = PlacingMode.NONE match tool_type: "tile": layers_panel.visible = true brush_panel.visible = true placing_mode = PlacingMode.TILEMAP func _set_brush(brush_type: String): current_brush = brush_type