Files
leo-game/addons/ez_tiles/ez_tiles.gd
2026-05-17 11:28:40 +02:00

213 lines
8.3 KiB
GDScript

@tool
extends EditorPlugin
class_name EZTiles
# importer
var dock : EZTilesDock
var alert_dialog : AcceptDialog
# draw
var selection : EditorSelection
var draw_dock : EZTilesDrawDock
var select_2D_viewport_button : Button
var select_mode_button : Button
var prev_tile_pos := Vector2i.ZERO
var lmb_is_down_outside_2d_viewport := false
var hint_polygon : Polygon2D
var prev_pos := Vector2i.ZERO
func _enter_tree() -> void:
# importer
dock = preload("res://addons/ez_tiles/ez_tiles_dock.tscn").instantiate()
add_control_to_bottom_panel(dock as Control, "EZ Tiles")
dock.request_tile_map_layer.connect(create_tile_map_layer_for_tile_set)
alert_dialog = AcceptDialog.new()
EditorInterface.get_base_control().add_child(alert_dialog)
# draw
draw_dock = preload("res://addons/ez_tiles/ez_tiles_draw/ez_tiles_draw_dock.tscn").instantiate()
selection = EditorInterface.get_selection()
selection.selection_changed.connect(handle_selected_node)
add_control_to_bottom_panel(draw_dock as Control, "EZ Tiles Draw")
handle_selected_node()
select_2D_viewport_button = EditorInterface.get_base_control().find_child("2D", true, false)
draw_dock.undo_redo = get_undo_redo()
# IMPORTER
func create_tile_map_layer_for_tile_set(tile_set : TileSet) -> void:
var root := EditorInterface.get_edited_scene_root()
if is_instance_valid(root) and root is Node2D:
var tile_map_layer := TileMapLayer.new()
tile_map_layer.tile_set = tile_set
tile_map_layer.name = "EZTilesTileMapLayer"
root.add_child(tile_map_layer, true)
tile_map_layer.set_owner(root)
tile_map_layer.set_meta("_is_ez_tiles_generated", true)
EditorInterface.edit_node(tile_map_layer)
else:
alert_dialog.title = "Warning!"
alert_dialog.dialog_text = """Cannot create TileMapLayer for this scene.
Please try again when editing a Node2D scene."""
alert_dialog.popup_centered()
# DRAW
func _handles(object: Object) -> bool:
return is_instance_valid(object) and object is TileMapLayer
func _dump_interface(n : Node, max_d : int = 2, d : int = 0) -> void:
if n.name.contains("Dialog") or n.name.contains("Popup"):
return
print(n.name.lpad(d + n.name.length(), "-") + " (%d)" % [n.get_child_count()])
for c in n.get_children():
if d < max_d:
_dump_interface(c, max_d, d + 1)
func _get_select_mode_button() -> Button:
if is_instance_valid(select_mode_button):
return select_mode_button
else:
select_mode_button = (
EditorInterface.get_editor_viewport_2d().find_parent("*CanvasItemEditor*")
.find_child("*Button*", true, false)
)
return select_mode_button
func _tile_pos_from_mouse_pos() -> Vector2i:
if not is_instance_valid(draw_dock.under_edit):
return Vector2i.ZERO
var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position()
var cursor_pos_on_tilemaplayer := (mouse_pos - draw_dock.under_edit.global_position).rotated(-draw_dock.under_edit.global_rotation)
var tile_pos := Vector2i(cursor_pos_on_tilemaplayer / (Vector2(draw_dock.under_edit.tile_set.tile_size) * draw_dock.under_edit.global_scale))
if cursor_pos_on_tilemaplayer.x < 0:
tile_pos.x -= 1
if cursor_pos_on_tilemaplayer.y < 0:
tile_pos.y -= 1
return tile_pos
func _tile_pos_to_overlay_pos(tile_pos : Vector2i) -> Vector2:
if not(draw_dock.visible and is_instance_valid(draw_dock.under_edit) and _get_select_mode_button().button_pressed):
return Vector2i.ZERO
return (
(
(
(Vector2(tile_pos) * (Vector2(draw_dock.under_edit.tile_set.tile_size) * draw_dock.under_edit.global_scale)).rotated(draw_dock.under_edit.global_rotation) + draw_dock.under_edit.global_position
) * EditorInterface.get_editor_viewport_2d().get_final_transform().get_scale()
) + EditorInterface.get_editor_viewport_2d().get_final_transform().get_origin()
)
func _forward_canvas_draw_over_viewport(overlay):
if lmb_is_down_outside_2d_viewport:
return
var viewport_2d := EditorInterface.get_editor_viewport_2d()
var g_mouse_pos = (
EditorInterface.get_base_control().get_global_mouse_position()
- viewport_2d.get_parent().global_position
)
if not viewport_2d.get_visible_rect().has_point(g_mouse_pos):
return
var fill := Color(1.0, 0.0, 0.0, 0.2) if draw_dock.rmb_is_down or draw_dock.using_eraser else Color(Color.WHITE, 0.2)
var stroke := Color.RED if draw_dock.rmb_is_down or draw_dock.using_eraser else Color.WHITE
var draw_rect := draw_dock.get_draw_rect(_tile_pos_from_mouse_pos())
var tl_corner := _tile_pos_to_overlay_pos(draw_rect.position)
var tr_corner := _tile_pos_to_overlay_pos(draw_rect.position + draw_rect.size * Vector2i.RIGHT)
var br_corner := _tile_pos_to_overlay_pos(draw_rect.position + draw_rect.size)
var bl_corner := _tile_pos_to_overlay_pos(draw_rect.position + draw_rect.size * Vector2i.DOWN)
overlay.draw_polyline(PackedVector2Array([tl_corner, tr_corner, br_corner, bl_corner, tl_corner]), stroke, 0.5, true)
if draw_dock.rmb_is_down or draw_dock.using_eraser:
overlay.draw_polygon(PackedVector2Array([tl_corner, tr_corner, br_corner, bl_corner, tl_corner]), [fill])
if draw_dock.drag_mode == EZTilesDrawDock.DragMode.BRUSH:
var draw_area := draw_dock.get_draw_area(_tile_pos_from_mouse_pos())
for tile in draw_area:
var tl := _tile_pos_to_overlay_pos(tile)
var tr := _tile_pos_to_overlay_pos(tile + Vector2i.RIGHT)
var br := _tile_pos_to_overlay_pos(tile + Vector2i.ONE)
var bl := _tile_pos_to_overlay_pos(tile + Vector2i.DOWN)
overlay.draw_polygon(PackedVector2Array([tl, tr, br, bl]), [fill])
else:
var draw_area := draw_dock.get_draw_area(_tile_pos_from_mouse_pos())
for tile in draw_area:
var tl := _tile_pos_to_overlay_pos(tile)
var tr := _tile_pos_to_overlay_pos(tile + Vector2i.RIGHT)
var br := _tile_pos_to_overlay_pos(tile + Vector2i.ONE)
var bl := _tile_pos_to_overlay_pos(tile + Vector2i.DOWN)
overlay.draw_polygon(PackedVector2Array([tl, tr, br, bl]), [fill])
func _input(_event) -> void:
update_overlays()
if is_instance_valid(draw_dock.under_edit) and select_2D_viewport_button.button_pressed and _get_select_mode_button().button_pressed and draw_dock.visible:
var viewport_2d := EditorInterface.get_editor_viewport_2d()
var g_mouse_pos = (
EditorInterface.get_base_control().get_global_mouse_position()
- viewport_2d.get_parent().global_position
)
if ((viewport_2d.get_visible_rect().has_point(g_mouse_pos)
and not lmb_is_down_outside_2d_viewport
and not (g_mouse_pos.x <= 164 and g_mouse_pos.y <= 40))
or draw_dock.lmb_is_down or draw_dock.rmb_is_down):
var tile_pos := _tile_pos_from_mouse_pos()
if (Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
and not draw_dock.lmb_is_down
and not lmb_is_down_outside_2d_viewport):
draw_dock.handle_mouse_down(MOUSE_BUTTON_LEFT, tile_pos)
if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) and not draw_dock.rmb_is_down:
draw_dock.handle_mouse_down(MOUSE_BUTTON_RIGHT, tile_pos)
if draw_dock.lmb_is_down and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
draw_dock.handle_mouse_up(MOUSE_BUTTON_LEFT, tile_pos)
if draw_dock.rmb_is_down and not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
draw_dock.handle_mouse_up(MOUSE_BUTTON_RIGHT, tile_pos)
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and draw_dock.lmb_is_down:
viewport_2d.set_input_as_handled()
elif Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
viewport_2d.set_input_as_handled()
if Input.is_key_pressed(KEY_CTRL):
draw_dock._place_back_remembered_cells()
draw_dock.suppress_preview = true
else:
draw_dock.suppress_preview = false
if not draw_dock.viewport_has_mouse:
draw_dock.handle_mouse_entered()
if prev_pos != tile_pos:
draw_dock.handle_mouse_move(tile_pos)
prev_pos = tile_pos
else:
lmb_is_down_outside_2d_viewport = Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
if draw_dock.viewport_has_mouse:
draw_dock.handle_mouse_out()
func handle_selected_node():
var selected_node : Node = selection.get_selected_nodes().pop_back()
if is_instance_valid(selected_node) and selected_node is TileMapLayer and is_instance_valid(selected_node.tile_set):
draw_dock.activate(selected_node)
if selected_node.has_meta("_is_ez_tiles_generated"):
await get_tree().create_timer(0.5).timeout
make_bottom_panel_item_visible(draw_dock)
else:
draw_dock.deactivate()
func _exit_tree() -> void:
remove_control_from_bottom_panel(dock)
dock.free()
remove_control_from_bottom_panel(draw_dock)
draw_dock.free()