diff options
author | Gilles Roudière <gilles.roudiere@gmail.com> | 2024-01-19 17:25:14 +0100 |
---|---|---|
committer | Gilles Roudière <gilles.roudiere@gmail.com> | 2024-02-12 10:11:45 +0100 |
commit | 5a999d67ec4116ba4e8845bcab13eef31a957606 (patch) | |
tree | 6a02cb1269f40139927eae8a888f147be0d80fa3 | |
parent | 4e990cd7e51d17cf24f854cc33b2715eaa27200f (diff) | |
download | redot-engine-5a999d67ec4116ba4e8845bcab13eef31a957606.tar.gz |
Change TileMapEditor to TileMapLayerEditor
-rw-r--r-- | doc/classes/TileMap.xml | 5 | ||||
-rw-r--r-- | doc/classes/TileMapLayerGroup.xml | 17 | ||||
-rw-r--r-- | editor/plugins/tiles/tile_map_layer_editor.cpp (renamed from editor/plugins/tiles/tile_map_editor.cpp) | 1342 | ||||
-rw-r--r-- | editor/plugins/tiles/tile_map_layer_editor.h (renamed from editor/plugins/tiles/tile_map_editor.h) | 79 | ||||
-rw-r--r-- | editor/plugins/tiles/tiles_editor_plugin.cpp | 152 | ||||
-rw-r--r-- | editor/plugins/tiles/tiles_editor_plugin.h | 16 | ||||
-rw-r--r-- | misc/extension_api_validation/4.2-stable.expected | 9 | ||||
-rw-r--r-- | scene/2d/tile_map.cpp | 317 | ||||
-rw-r--r-- | scene/2d/tile_map.h | 26 | ||||
-rw-r--r-- | scene/2d/tile_map_layer.cpp | 322 | ||||
-rw-r--r-- | scene/2d/tile_map_layer.h | 33 | ||||
-rw-r--r-- | scene/2d/tile_map_layer_group.cpp | 148 | ||||
-rw-r--r-- | scene/2d/tile_map_layer_group.h | 73 | ||||
-rw-r--r-- | scene/register_scene_types.cpp | 1 | ||||
-rw-r--r-- | scene/resources/tile_set.cpp | 191 | ||||
-rw-r--r-- | scene/resources/tile_set.h | 13 |
16 files changed, 1496 insertions, 1248 deletions
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index b08eb5c013..695ffca1a3 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TileMap" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="TileMap" inherits="TileMapLayerGroup" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node for 2D tile-based maps. </brief_description> @@ -488,9 +488,6 @@ The quadrant size does not apply on Y-sorted layers, as tiles are be grouped by Y position instead in that case. [b]Note:[/b] As quadrants are created according to the map's coordinate system, the quadrant's "square shape" might not look like square in the TileMap's local coordinate system. </member> - <member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset"> - The assigned [TileSet]. - </member> </members> <signals> <signal name="changed"> diff --git a/doc/classes/TileMapLayerGroup.xml b/doc/classes/TileMapLayerGroup.xml new file mode 100644 index 0000000000..3787d3bb17 --- /dev/null +++ b/doc/classes/TileMapLayerGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="TileMapLayerGroup" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Groups a set of tile map layers together, allowing them to share a provided [TileSet]. + </brief_description> + <description> + Groups together tile map layers as part or the same map, replacing the [TileMap] node. Child layers will use this node's [member tile_set]. + The editor also uses [TileMapLayerGroup] as a way to store which layers are selected in a given group. This allows highlighting the currently selected layers. + </description> + <tutorials> + </tutorials> + <members> + <member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset"> + The assigned [TileSet]. This TileSet will be applied to all child layers. + </member> + </members> +</class> diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index c34878b54e..1551fabc0c 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* tile_map_editor.cpp */ +/* tile_map_layer_editor.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "tile_map_editor.h" +#include "tile_map_layer_editor.h" #include "tiles_editor_plugin.h" @@ -40,6 +40,7 @@ #include "editor/themes/editor_scale.h" #include "scene/2d/camera_2d.h" +#include "scene/2d/tile_map_layer.h" #include "scene/gui/center_container.h" #include "scene/gui/split_container.h" @@ -47,22 +48,26 @@ #include "core/math/geometry_2d.h" #include "core/os/keyboard.h" -void TileMapEditorTilesPlugin::tile_set_changed() { +TileMapLayer *TileMapLayerSubEditorPlugin::_get_edited_layer() const { + return Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id)); +} + +void TileMapLayerEditorTilesPlugin::tile_set_changed() { _update_fix_selected_and_hovered(); _update_tile_set_sources_list(); _update_source_display(); _update_patterns_list(); } -void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) { +void TileMapLayerEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) { scatter_controls_container->set_visible(p_pressed); } -void TileMapEditorTilesPlugin::_on_scattering_spinbox_changed(double p_value) { +void TileMapLayerEditorTilesPlugin::_on_scattering_spinbox_changed(double p_value) { scattering = p_value; } -void TileMapEditorTilesPlugin::_update_toolbar() { +void TileMapLayerEditorTilesPlugin::_update_toolbar() { // Stop draggig if needed. _stop_dragging(); @@ -96,13 +101,13 @@ void TileMapEditorTilesPlugin::_update_toolbar() { } } -void TileMapEditorTilesPlugin::_update_transform_buttons() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_transform_buttons() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); if (tile_set.is_null() || selection_pattern.is_null()) { return; } @@ -126,7 +131,7 @@ void TileMapEditorTilesPlugin::_update_transform_buttons() { } } -void TileMapEditorTilesPlugin::_set_transform_buttons_state(const Vector<Button *> &p_enabled_buttons, const Vector<Button *> &p_disabled_buttons, const String &p_why_disabled) { +void TileMapLayerEditorTilesPlugin::_set_transform_buttons_state(const Vector<Button *> &p_enabled_buttons, const Vector<Button *> &p_disabled_buttons, const String &p_why_disabled) { for (Button *button : p_enabled_buttons) { button->set_disabled(false); button->set_tooltip_text(""); @@ -137,14 +142,14 @@ void TileMapEditorTilesPlugin::_set_transform_buttons_state(const Vector<Button } } -Vector<TileMapSubEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const { - Vector<TileMapSubEditorPlugin::TabData> tabs; +Vector<TileMapLayerSubEditorPlugin::TabData> TileMapLayerEditorTilesPlugin::get_tabs() const { + Vector<TileMapLayerSubEditorPlugin::TabData> tabs; tabs.push_back({ toolbar, tiles_bottom_panel }); tabs.push_back({ toolbar, patterns_bottom_panel }); return tabs; } -void TileMapEditorTilesPlugin::_tab_changed() { +void TileMapLayerEditorTilesPlugin::_tab_changed() { if (tiles_bottom_panel->is_visible_in_tree()) { _update_selection_pattern_from_tileset_tiles_selection(); } else if (patterns_bottom_panel->is_visible_in_tree()) { @@ -152,7 +157,7 @@ void TileMapEditorTilesPlugin::_tab_changed() { } } -void TileMapEditorTilesPlugin::_update_tile_set_sources_list() { +void TileMapLayerEditorTilesPlugin::_update_tile_set_sources_list() { // Update the sources. int old_current = sources_list->get_current(); int old_source = -1; @@ -161,13 +166,13 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() { } sources_list->clear(); - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -244,15 +249,15 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() { TilesEditorUtils::get_singleton()->set_sources_lists_current(sources_list->get_current()); } -void TileMapEditorTilesPlugin::_update_source_display() { +void TileMapLayerEditorTilesPlugin::_update_source_display() { // Update the atlas display. - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -291,14 +296,14 @@ void TileMapEditorTilesPlugin::_update_source_display() { } } -void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid() || EditorNode::get_singleton()->is_resource_read_only(tile_set)) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -327,7 +332,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven } } -void TileMapEditorTilesPlugin::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) { +void TileMapLayerEditorTilesPlugin::_pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture) { // TODO optimize ? for (int i = 0; i < patterns_item_list->get_item_count(); i++) { if (patterns_item_list->get_item_metadata(i) == p_pattern) { @@ -337,14 +342,14 @@ void TileMapEditorTilesPlugin::_pattern_preview_done(Ref<TileMapPattern> p_patte } } -void TileMapEditorTilesPlugin::_update_patterns_list() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_patterns_list() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -354,7 +359,7 @@ void TileMapEditorTilesPlugin::_update_patterns_list() { int id = patterns_item_list->add_item(""); patterns_item_list->set_item_metadata(id, tile_set->get_pattern(i)); patterns_item_list->set_item_tooltip(id, vformat(TTR("Index: %d"), i)); - TilesEditorUtils::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapEditorTilesPlugin::_pattern_preview_done)); + TilesEditorUtils::get_singleton()->queue_pattern_preview(tile_set, tile_set->get_pattern(i), callable_mp(this, &TileMapLayerEditorTilesPlugin::_pattern_preview_done)); } // Update the label visibility. @@ -369,14 +374,14 @@ void TileMapEditorTilesPlugin::_update_patterns_list() { select_last_pattern = false; } -void TileMapEditorTilesPlugin::_update_atlas_view() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_atlas_view() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -385,19 +390,19 @@ void TileMapEditorTilesPlugin::_update_atlas_view() { TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); ERR_FAIL_NULL(atlas_source); - tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id); + tile_atlas_view->set_atlas_source(*tile_set, atlas_source, source_id); TilesEditorUtils::get_singleton()->synchronize_atlas_view(tile_atlas_view); tile_atlas_control->queue_redraw(); } -void TileMapEditorTilesPlugin::_update_scenes_collection_view() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_scenes_collection_view() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -440,7 +445,7 @@ void TileMapEditorTilesPlugin::_update_scenes_collection_view() { scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size)); } -void TileMapEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) { +void TileMapLayerEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) { int index = p_ud; if (index >= 0 && index < scene_tiles_list->get_item_count()) { @@ -448,14 +453,14 @@ void TileMapEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const } } -void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_selected) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_selected) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -484,7 +489,7 @@ void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_s _update_selection_pattern_from_tileset_tiles_selection(); } -void TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index) { +void TileMapLayerEditorTilesPlugin::_scenes_list_lmb_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index) { if (p_mouse_button_index != MouseButton::LEFT) { return; } @@ -496,7 +501,7 @@ void TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked(const Vector2 &p_p _update_selection_pattern_from_tileset_tiles_selection(); } -void TileMapEditorTilesPlugin::_update_theme() { +void TileMapLayerEditorTilesPlugin::_update_theme() { source_sort_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Sort"))); select_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("ToolSelect"))); paint_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Edit"))); @@ -517,7 +522,7 @@ void TileMapEditorTilesPlugin::_update_theme() { _update_tile_set_sources_list(); } -bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { +bool TileMapLayerEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (!(tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree())) { // If the bottom editor is not visible, we ignore inputs. return false; @@ -528,18 +533,13 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p return false; } - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return false; } - if (tile_map_layer < 0) { - return false; - } - ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), false); - - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return false; } @@ -552,7 +552,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p for (const Vector2i &E : tile_map_selection) { coords_array.push_back(E); } - tile_map_clipboard = tile_map->get_pattern(tile_map_layer, coords_array); + tile_map_clipboard = edited_layer->get_pattern(coords_array); } if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) { @@ -560,9 +560,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (!tile_map_selection.is_empty()) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete tiles")); - for (const Vector2i &E : tile_map_selection) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E, tile_map->get_cell_source_id(tile_map_layer, E), tile_map->get_cell_atlas_coords(tile_map_layer, E), tile_map->get_cell_alternative_tile(tile_map_layer, E)); + for (const Vector2i &coords : tile_map_selection) { + undo_redo->add_do_method(edited_layer, "set_cell", coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + undo_redo->add_undo_method(edited_layer, "set_cell", coords, edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); tile_map_selection.clear(); @@ -592,9 +592,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (!tile_map_selection.is_empty()) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete tiles")); - for (const Vector2i &E : tile_map_selection) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E, tile_map->get_cell_source_id(tile_map_layer, E), tile_map->get_cell_atlas_coords(tile_map_layer, E), tile_map->get_cell_alternative_tile(tile_map_layer, E)); + for (const Vector2i &coords : tile_map_selection) { + undo_redo->add_do_method(edited_layer, "set_cell", coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + undo_redo->add_undo_method(edited_layer, "set_cell", coords, edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); tile_map_selection.clear(); @@ -626,7 +626,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { has_mouse = true; - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(mm->get_position()); switch (drag_type) { @@ -635,28 +635,28 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { Vector2i coords = E.key; if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + drag_modified.insert(coords, edited_layer->get_cell(coords)); if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } _fix_invalid_tiles_in_tile_map_selection(); } break; case DRAG_TYPE_BUCKET: { - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos)); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, tile_set->local_to_map(drag_last_mouse_pos), tile_set->local_to_map(mpos)); for (int i = 0; i < line.size(); i++) { if (!drag_modified.has(line[i])) { HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { Vector2i coords = E.key; if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + drag_modified.insert(coords, edited_layer->get_cell(coords)); if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } } @@ -675,7 +675,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { has_mouse = true; - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(mb->get_position()); if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) { @@ -692,15 +692,15 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } } else if (tool_buttons_group->get_pressed_button() == select_tool_button) { drag_start_mouse_pos = mpos; - if (tile_map_selection.has(tile_map->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed()) { + if (tile_map_selection.has(tile_set->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed()) { // Move the selection _update_selection_pattern_from_tilemap_selection(); // Make sure the pattern is up to date before moving. drag_type = DRAG_TYPE_MOVE; drag_modified.clear(); for (const Vector2i &E : tile_map_selection) { Vector2i coords = E; - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); - tile_map->set_cell(tile_map_layer, coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + drag_modified.insert(coords, edited_layer->get_cell(coords)); + edited_layer->set_cell(coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); } } else { // Select tiles @@ -724,9 +724,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } Vector2i coords = E.key; if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + drag_modified.insert(coords, edited_layer->get_cell(coords)); } - tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } _fix_invalid_tiles_in_tile_map_selection(); } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { @@ -741,18 +741,18 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p drag_type = DRAG_TYPE_BUCKET; drag_start_mouse_pos = mpos; drag_modified.clear(); - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos)); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, tile_set->local_to_map(drag_last_mouse_pos), tile_set->local_to_map(mpos)); for (int i = 0; i < line.size(); i++) { if (!drag_modified.has(line[i])) { HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { Vector2i coords = E.key; if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + drag_modified.insert(coords, edited_layer->get_cell(coords)); if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } } @@ -778,28 +778,23 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p return false; } -void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { - return; - } - - if (tile_map_layer < 0) { +void TileMapLayerEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - if (!tile_map->is_visible_in_tree()) { + if (!edited_layer->is_visible_in_tree()) { return; } - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); - Vector2 mpos = tile_map->get_local_mouse_position(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); + Vector2 mpos = edited_layer->get_local_mouse_position(); Vector2i tile_shape_size = tile_set->get_tile_size(); // Draw the selection. @@ -810,7 +805,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over } else { Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); - tile_map->draw_cells_outline(p_overlay, tile_map_selection, selection_color, xform); + tile_set->draw_cells_outline(p_overlay, tile_map_selection, selection_color, xform); } } @@ -821,33 +816,33 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over if (drag_type == DRAG_TYPE_PICK) { // Draw the area being picked. - Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs(); + Rect2i rect = Rect2i(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos) - tile_set->local_to_map(drag_start_mouse_pos)).abs(); rect.size += Vector2i(1, 1); for (int x = rect.position.x; x < rect.get_end().x; x++) { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { - Transform2D tile_xform(0, tile_shape_size, 0, tile_map->map_to_local(coords)); + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { + Transform2D tile_xform(0, tile_shape_size, 0, tile_set->map_to_local(coords)); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false); } } } } else if (drag_type == DRAG_TYPE_SELECT) { // Draw the area being selected. - Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs(); + Rect2i rect = Rect2i(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos) - tile_set->local_to_map(drag_start_mouse_pos)).abs(); rect.size += Vector2i(1, 1); RBSet<Vector2i> to_draw; for (int x = rect.position.x; x < rect.get_end().x; x++) { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { to_draw.insert(coords); } - Transform2D tile_xform(0, tile_shape_size, 0, tile_map->map_to_local(coords)); + Transform2D tile_xform(0, tile_shape_size, 0, tile_set->map_to_local(coords)); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.2), true); } } - tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform); + tile_set->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform); } else if (drag_type == DRAG_TYPE_MOVE) { if (!(patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position()))) { // Preview when moving. @@ -858,12 +853,12 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over for (const Vector2i &E : tile_map_selection) { top_left = top_left.min(E); } - Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left); - offset = tile_map->local_to_map(mpos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset); + Vector2i offset = drag_start_mouse_pos - tile_set->map_to_local(top_left); + offset = tile_set->local_to_map(mpos - offset) - tile_set->local_to_map(drag_start_mouse_pos - offset); TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells(); for (int i = 0; i < selection_used_cells.size(); i++) { - Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern); + Vector2i coords = tile_set->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern); preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i])); } } @@ -872,7 +867,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over Vector2 mouse_offset = (Vector2(tile_map_clipboard->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); TypedArray<Vector2i> clipboard_used_cells = tile_map_clipboard->get_used_cells(); for (int i = 0; i < clipboard_used_cells.size(); i++) { - Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(mpos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard); + Vector2i coords = tile_set->map_pattern(tile_set->local_to_map(mpos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard); preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i])); } } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { @@ -893,11 +888,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over } } else if (drag_type == DRAG_TYPE_RECT) { // Preview for a rect pattern. - preview = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing); + preview = _draw_rect(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos), drag_erasing); expand_grid = true; } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) { // Preview for a fill pattern. - preview = _draw_bucket_fill(tile_map->local_to_map(mpos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed()); + preview = _draw_bucket_fill(tile_set->local_to_map(mpos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed()); } // Expand the grid if needed @@ -931,7 +926,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y))); + tile_xform.set_origin(tile_set->map_to_local(Vector2(x, y))); tile_xform.set_scale(tile_shape_size); Color color = grid_color; color.a = color.a * opacity; @@ -944,7 +939,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over // Draw the preview. for (const KeyValue<Vector2i, TileMapCell> &E : preview) { Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(E.key)); + tile_xform.set_origin(tile_set->map_to_local(E.key)); tile_xform.set_scale(tile_set->get_tile_size()); if (!(drag_erasing || erase_button->is_pressed()) && random_tile_toggle->is_pressed()) { tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true); @@ -969,9 +964,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over bool transpose = tile_data->get_transpose() ^ bool(E.value.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); if (transpose) { - dest_rect.position = (tile_map->map_to_local(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset); + dest_rect.position = (tile_set->map_to_local(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset); } else { - dest_rect.position = (tile_map->map_to_local(E.key) - dest_rect.size / 2 - tile_offset); + dest_rect.position = (tile_set->map_to_local(E.key) - dest_rect.size / 2 - tile_offset); } if (tile_data->get_flip_h() ^ bool(E.value.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) { @@ -983,10 +978,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over } // Get the tile modulation. - Color modulate = tile_data->get_modulate(); - Color self_modulate = tile_map->get_modulate_in_tree() * tile_map->get_self_modulate(); - modulate *= self_modulate; - modulate *= tile_map->get_layer_modulate(tile_map_layer); + Color modulate = tile_data->get_modulate() * edited_layer->get_modulate_in_tree() * edited_layer->get_self_modulate(); // Draw the tile. p_overlay->draw_set_transform_matrix(xform); @@ -1006,9 +998,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over int font_size = p_overlay->get_theme_font_size(SNAME("font_size"), SNAME("Label")); Point2 msgpos = Point2(20 * EDSCALE, p_overlay->get_size().y - 20 * EDSCALE); - String text = tile_map->local_to_map(tile_map->get_local_mouse_position()); + String text = tile_set->local_to_map(edited_layer->get_local_mouse_position()); if (drag_type == DRAG_TYPE_RECT) { - Vector2i size = tile_map->local_to_map(tile_map->get_local_mouse_position()) - tile_map->local_to_map(drag_start_mouse_pos); + Vector2i size = tile_set->local_to_map(edited_layer->get_local_mouse_position()) - tile_set->local_to_map(drag_start_mouse_pos); text += vformat(" %s (%dx%d)", TTR("Drawing Rect:"), ABS(size.x) + 1, ABS(size.y) + 1); } @@ -1018,19 +1010,19 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over } } -void TileMapEditorTilesPlugin::_mouse_exited_viewport() { +void TileMapLayerEditorTilesPlugin::_mouse_exited_viewport() { has_mouse = false; CanvasItemEditor::get_singleton()->update_viewport(); } -TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pattern) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +TileMapCell TileMapLayerEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pattern) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return TileMapCell(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return TileMapCell(); } @@ -1075,14 +1067,14 @@ TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pa return TileMapCell(); } -HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos, bool p_erase) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -1097,7 +1089,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st // Paint the tiles on the tile map. if (!p_erase && random_tile_toggle->is_pressed()) { // Paint a random tile. - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(p_from_mouse_pos), tile_map->local_to_map(p_to_mouse_pos)); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, tile_set->local_to_map(p_from_mouse_pos), tile_set->local_to_map(p_to_mouse_pos)); for (int i = 0; i < line.size(); i++) { output.insert(line[i], _pick_random_tile(pattern)); } @@ -1105,17 +1097,17 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st // Paint the pattern. // If we paint several tiles, we virtually move the mouse as if it was in the center of the "brush" Vector2 mouse_offset = (Vector2(pattern->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); - Vector2i last_hovered_cell = tile_map->local_to_map(p_from_mouse_pos - mouse_offset); - Vector2i new_hovered_cell = tile_map->local_to_map(p_to_mouse_pos - mouse_offset); - Vector2i drag_start_cell = tile_map->local_to_map(p_start_drag_mouse_pos - mouse_offset); + Vector2i last_hovered_cell = tile_set->local_to_map(p_from_mouse_pos - mouse_offset); + Vector2i new_hovered_cell = tile_set->local_to_map(p_to_mouse_pos - mouse_offset); + Vector2i drag_start_cell = tile_set->local_to_map(p_start_drag_mouse_pos - mouse_offset); TypedArray<Vector2i> used_cells = pattern->get_used_cells(); Vector2i offset = Vector2i(Math::posmod(drag_start_cell.x, pattern->get_size().x), Math::posmod(drag_start_cell.y, pattern->get_size().y)); // Note: no posmodv for Vector2i for now. Meh.s - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, (last_hovered_cell - offset) / pattern->get_size(), (new_hovered_cell - offset) / pattern->get_size()); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, (last_hovered_cell - offset) / pattern->get_size(), (new_hovered_cell - offset) / pattern->get_size()); for (int i = 0; i < line.size(); i++) { Vector2i top_left = line[i] * pattern->get_size() + offset; for (int j = 0; j < used_cells.size(); j++) { - Vector2i coords = tile_map->map_pattern(top_left, used_cells[j], pattern); + Vector2i coords = tile_set->map_pattern(top_left, used_cells[j], pattern); output.insert(coords, TileMapCell(pattern->get_cell_source_id(used_cells[j]), pattern->get_cell_atlas_coords(used_cells[j]), pattern->get_cell_alternative_tile(used_cells[j]))); } } @@ -1124,14 +1116,14 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st return output; } -HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -1183,22 +1175,18 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_s return output; } -HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - if (tile_map_layer < 0) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } - HashMap<Vector2i, TileMapCell> output; - ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), output); - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { - return HashMap<Vector2i, TileMapCell>(); - } + HashMap<Vector2i, TileMapCell> output; // Get or create the pattern. Ref<TileMapPattern> erase_pattern; @@ -1207,12 +1195,12 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto Ref<TileMapPattern> pattern = p_erase ? erase_pattern : selection_pattern; if (!pattern->is_empty()) { - TileMapCell source_cell = tile_map->get_cell(tile_map_layer, p_coords); + TileMapCell source_cell = edited_layer->get_cell(p_coords); // If we are filling empty tiles, compute the tilemap boundaries. Rect2i boundaries; if (source_cell.source_id == TileSet::INVALID_SOURCE) { - boundaries = tile_map->get_used_rect(); + boundaries = edited_layer->get_used_rect(); } if (p_contiguous) { @@ -1224,9 +1212,9 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto Vector2i coords = to_check.back()->get(); to_check.pop_back(); if (!already_checked.has(coords)) { - if (source_cell.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) && - source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) && - source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) && + if (source_cell.source_id == edited_layer->get_cell_source_id(coords) && + source_cell.get_atlas_coords() == edited_layer->get_cell_atlas_coords(coords) && + source_cell.alternative_tile == edited_layer->get_cell_alternative_tile(coords) && (source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) { if (!p_erase && random_tile_toggle->is_pressed()) { // Paint a random tile. @@ -1244,7 +1232,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto } // Get surrounding tiles (handles different tile shapes). - TypedArray<Vector2i> around = tile_map->get_surrounding_cells(coords); + TypedArray<Vector2i> around = tile_set->get_surrounding_cells(coords); for (int i = 0; i < around.size(); i++) { to_check.push_back(around[i]); } @@ -1256,7 +1244,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto // Replace all tiles like the source. TypedArray<Vector2i> to_check; if (source_cell.source_id == TileSet::INVALID_SOURCE) { - Rect2i rect = tile_map->get_used_rect(); + Rect2i rect = edited_layer->get_used_rect(); if (!rect.has_area()) { rect = Rect2i(p_coords, Vector2i(1, 1)); } @@ -1266,13 +1254,13 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto } } } else { - to_check = tile_map->get_used_cells(tile_map_layer); + to_check = edited_layer->get_used_cells(); } for (int i = 0; i < to_check.size(); i++) { Vector2i coords = to_check[i]; - if (source_cell.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) && - source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) && - source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) && + if (source_cell.source_id == edited_layer->get_cell_source_id(coords) && + source_cell.get_atlas_coords() == edited_layer->get_cell_atlas_coords(coords) && + source_cell.alternative_tile == edited_layer->get_cell_alternative_tile(coords) && (source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) { if (!p_erase && random_tile_toggle->is_pressed()) { // Paint a random tile. @@ -1295,27 +1283,22 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto return output; } -void TileMapEditorTilesPlugin::_stop_dragging() { +void TileMapLayerEditorTilesPlugin::_stop_dragging() { if (drag_type == DRAG_TYPE_NONE) { return; } - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - if (tile_map_layer < 0) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { - return; - } - - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position()); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); @@ -1327,7 +1310,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) { tile_map_selection.clear(); } - Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs(); + Rect2i rect = Rect2i(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos) - tile_set->local_to_map(drag_start_mouse_pos)).abs(); for (int x = rect.position.x; x <= rect.get_end().x; x++) { for (int y = rect.position.y; y <= rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); @@ -1336,7 +1319,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { tile_map_selection.erase(coords); } } else { - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { tile_map_selection.insert(coords); } } @@ -1352,7 +1335,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { if (patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position())) { // Restore the cells. for (KeyValue<Vector2i, TileMapCell> kv : drag_modified) { - tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile); + edited_layer->set_cell(kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile); } if (!EditorNode::get_singleton()->is_resource_read_only(tile_set)) { @@ -1375,8 +1358,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() { } // Get the offset from the mouse. - Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left); - offset = tile_map->local_to_map(mpos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset); + Vector2i offset = drag_start_mouse_pos - tile_set->map_to_local(top_left); + offset = tile_set->local_to_map(mpos - offset) - tile_set->local_to_map(drag_start_mouse_pos - offset); TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells(); @@ -1384,37 +1367,37 @@ void TileMapEditorTilesPlugin::_stop_dragging() { Vector2i coords; HashMap<Vector2i, TileMapCell> cells_undo; for (int i = 0; i < selection_used_cells.size(); i++) { - coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern); + coords = tile_set->map_pattern(top_left, selection_used_cells[i], selection_pattern); cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile); - coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); - cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); + coords = tile_set->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); + cells_undo[coords] = TileMapCell(edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } // Build the list of cells to do. HashMap<Vector2i, TileMapCell> cells_do; for (int i = 0; i < selection_used_cells.size(); i++) { - coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern); + coords = tile_set->map_pattern(top_left, selection_used_cells[i], selection_pattern); cells_do[coords] = TileMapCell(); } for (int i = 0; i < selection_used_cells.size(); i++) { - coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); + coords = tile_set->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i])); } // Move the tiles. undo_redo->create_action(TTR("Move tiles")); for (const KeyValue<Vector2i, TileMapCell> &E : cells_do) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } for (const KeyValue<Vector2i, TileMapCell> &E : cells_undo) { - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } // Update the selection. undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); tile_map_selection.clear(); for (int i = 0; i < selection_used_cells.size(); i++) { - coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); + coords = tile_set->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern); tile_map_selection.insert(coords); } undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection()); @@ -1422,7 +1405,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { } } break; case DRAG_TYPE_PICK: { - Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs(); + Rect2i rect = Rect2i(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos) - tile_set->local_to_map(drag_start_mouse_pos)).abs(); rect.size += Vector2i(1, 1); int picked_source = -1; @@ -1431,7 +1414,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { for (int y = rect.position.y; y < rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - int source = tile_map->get_cell_source_id(tile_map_layer, coords); + int source = edited_layer->get_cell_source_id(coords); if (source != TileSet::INVALID_SOURCE) { coords_array.push_back(coords); if (picked_source == -1) { @@ -1454,7 +1437,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { sources_list->ensure_current_is_visible(); } - Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array); + Ref<TileMapPattern> new_selection_pattern = edited_layer->get_pattern(coords_array); if (!new_selection_pattern->is_empty()) { selection_pattern = new_selection_pattern; _update_tileset_selection_from_selection_pattern(); @@ -1464,8 +1447,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() { case DRAG_TYPE_PAINT: { undo_redo->create_action(TTR("Paint tiles")); for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } undo_redo->commit_action(false); } break; @@ -1476,28 +1459,28 @@ void TileMapEditorTilesPlugin::_stop_dragging() { if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); } undo_redo->commit_action(); } break; case DRAG_TYPE_RECT: { - HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing); + HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos), drag_erasing); undo_redo->create_action(TTR("Paint tiles")); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); } undo_redo->commit_action(); } break; case DRAG_TYPE_BUCKET: { undo_redo->create_action(TTR("Paint tiles")); for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } undo_redo->commit_action(false); } break; @@ -1506,9 +1489,9 @@ void TileMapEditorTilesPlugin::_stop_dragging() { undo_redo->create_action(TTR("Paste tiles")); TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells(); for (int i = 0; i < used_cells.size(); i++) { - Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard); - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i])); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); + Vector2i coords = tile_set->map_pattern(tile_set->local_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard); + undo_redo->add_do_method(edited_layer, "set_cell", coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i])); + undo_redo->add_undo_method(edited_layer, "set_cell", coords, edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } undo_redo->commit_action(); } break; @@ -1518,7 +1501,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() { drag_type = DRAG_TYPE_NONE; } -void TileMapEditorTilesPlugin::_apply_transform(int p_type) { +void TileMapLayerEditorTilesPlugin::_apply_transform(int p_type) { if (selection_pattern.is_null() || selection_pattern->is_empty()) { return; } @@ -1558,7 +1541,7 @@ void TileMapEditorTilesPlugin::_apply_transform(int p_type) { CanvasItemEditor::get_singleton()->update_viewport(); } -int TileMapEditorTilesPlugin::_get_transformed_alternative(int p_alternative_id, int p_transform) { +int TileMapLayerEditorTilesPlugin::_get_transformed_alternative(int p_alternative_id, int p_transform) { bool transform_flip_h = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H; bool transform_flip_v = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V; bool transform_transpose = p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE; @@ -1606,9 +1589,9 @@ int TileMapEditorTilesPlugin::_get_transformed_alternative(int p_alternative_id, int(transform_transpose) * TileSetAtlasSource::TRANSFORM_TRANSPOSE; } -void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_fix_selected_and_hovered() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { hovered_tile.source_id = TileSet::INVALID_SOURCE; hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; @@ -1618,9 +1601,8 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() { selection_pattern.instantiate(); return; } - - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { hovered_tile.source_id = TileSet::INVALID_SOURCE; hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; @@ -1676,15 +1658,15 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() { } } -void TileMapEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } RBSet<Vector2i> to_remove; for (Vector2i selected : tile_map_selection) { - TileMapCell cell = tile_map->get_cell(tile_map_layer, selected); + TileMapCell cell = edited_layer->get_cell(selected); if (cell.source_id == TileSet::INVALID_SOURCE && cell.get_atlas_coords() == TileSetSource::INVALID_ATLAS_COORDS && cell.alternative_tile == TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) { to_remove.insert(selected); } @@ -1694,43 +1676,41 @@ void TileMapEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() { tile_map_selection.erase(cell); } } -void TileMapEditorTilesPlugin::patterns_item_list_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index) { +void TileMapLayerEditorTilesPlugin::patterns_item_list_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index) { if (p_mouse_button_index == MouseButton::LEFT) { _update_selection_pattern_from_tileset_pattern_selection(); } } -void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); - selection_pattern.instantiate(); TypedArray<Vector2i> coords_array; for (const Vector2i &E : tile_map_selection) { coords_array.push_back(E); } - selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array); + selection_pattern = edited_layer->get_pattern(coords_array); _update_transform_buttons(); } -void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_selection() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -1797,14 +1777,14 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_sele _update_transform_buttons(); } -void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -1821,7 +1801,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_se CanvasItemEditor::get_singleton()->update_viewport(); } -void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() { +void TileMapLayerEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() { tile_set_selection.clear(); TypedArray<Vector2i> used_cells = selection_pattern->get_used_cells(); for (int i = 0; i < used_cells.size(); i++) { @@ -1836,14 +1816,14 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern( _update_transform_buttons(); } -void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_tile_atlas_control_draw() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -1908,21 +1888,21 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { } } -void TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited() { +void TileMapLayerEditorTilesPlugin::_tile_atlas_control_mouse_exited() { hovered_tile.source_id = TileSet::INVALID_SOURCE; hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; tile_atlas_control->queue_redraw(); } -void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -2021,14 +2001,14 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven } } -void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_draw() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -2066,21 +2046,21 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() { } } -void TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited() { +void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_mouse_exited() { hovered_tile.source_id = TileSet::INVALID_SOURCE; hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; alternative_tiles_control->queue_redraw(); } -void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -2139,7 +2119,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In } } -void TileMapEditorTilesPlugin::_set_tile_map_selection(const TypedArray<Vector2i> &p_selection) { +void TileMapLayerEditorTilesPlugin::_set_tile_map_selection(const TypedArray<Vector2i> &p_selection) { tile_map_selection.clear(); for (int i = 0; i < p_selection.size(); i++) { tile_map_selection.insert(p_selection[i]); @@ -2149,7 +2129,7 @@ void TileMapEditorTilesPlugin::_set_tile_map_selection(const TypedArray<Vector2i CanvasItemEditor::get_singleton()->update_viewport(); } -TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const { +TypedArray<Vector2i> TileMapLayerEditorTilesPlugin::_get_tile_map_selection() const { TypedArray<Vector2i> output; for (const Vector2i &E : tile_map_selection) { output.push_back(E); @@ -2157,20 +2137,35 @@ TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const { return output; } -void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { +void TileMapLayerEditorTilesPlugin::_set_source_sort(int p_sort) { + for (int i = 0; i != TilesEditorUtils::SOURCE_SORT_MAX; i++) { + source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort)); + } + TilesEditorUtils::get_singleton()->set_sorting_option(p_sort); + _update_tile_set_sources_list(); + EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "tile_source_sort", p_sort); +} + +void TileMapLayerEditorTilesPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileMapLayerEditorTilesPlugin::_scene_thumbnail_done); + ClassDB::bind_method(D_METHOD("_set_tile_map_selection", "selection"), &TileMapLayerEditorTilesPlugin::_set_tile_map_selection); + ClassDB::bind_method(D_METHOD("_get_tile_map_selection"), &TileMapLayerEditorTilesPlugin::_get_tile_map_selection); +} + +void TileMapLayerEditorTilesPlugin::edit(ObjectID p_tile_map_layer_id) { _stop_dragging(); // Avoids staying in a wrong drag state. // Disable sort button if the tileset is read-only - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (tile_map) { - Ref<TileSet> tile_set = tile_map->get_tileset(); + TileMapLayer *edited_layer = _get_edited_layer(); + if (edited_layer) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); if (tile_set.is_valid()) { source_sort_button->set_disabled(EditorNode::get_singleton()->is_resource_read_only(tile_set)); } } - if (tile_map_id != p_tile_map_id) { - tile_map_id = p_tile_map_id; + if (edited_tile_map_layer_id != p_tile_map_layer_id) { + edited_tile_map_layer_id = p_tile_map_layer_id; // Clear the selection. tile_set_selection.clear(); @@ -2179,28 +2174,13 @@ void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer selection_pattern.instantiate(); } - tile_map_layer = p_tile_map_layer; + edited_tile_map_layer_id = p_tile_map_layer_id; } -void TileMapEditorTilesPlugin::_set_source_sort(int p_sort) { - for (int i = 0; i != TilesEditorUtils::SOURCE_SORT_MAX; i++) { - source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort)); - } - TilesEditorUtils::get_singleton()->set_sorting_option(p_sort); - _update_tile_set_sources_list(); - EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "tile_source_sort", p_sort); -} - -void TileMapEditorTilesPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileMapEditorTilesPlugin::_scene_thumbnail_done); - ClassDB::bind_method(D_METHOD("_set_tile_map_selection", "selection"), &TileMapEditorTilesPlugin::_set_tile_map_selection); - ClassDB::bind_method(D_METHOD("_get_tile_map_selection"), &TileMapEditorTilesPlugin::_get_tile_map_selection); -} - -TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { +TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() { CanvasItemEditor::get_singleton() ->get_viewport_control() - ->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_mouse_exited_viewport)); + ->connect("mouse_exited", callable_mp(this, &TileMapLayerEditorTilesPlugin::_mouse_exited_viewport)); // --- Shortcuts --- ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X); @@ -2225,7 +2205,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { select_tool_button->set_toggle_mode(true); select_tool_button->set_button_group(tool_buttons_group); select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", TTR("Selection"), Key::S)); - select_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); + select_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(select_tool_button); viewport_shortcut_buttons.push_back(select_tool_button); @@ -2235,7 +2215,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { paint_tool_button->set_button_group(tool_buttons_group); paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D)); paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Shift: Draw rectangle.")); - paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); + paint_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(paint_tool_button); viewport_shortcut_buttons.push_back(paint_tool_button); @@ -2245,7 +2225,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { line_tool_button->set_button_group(tool_buttons_group); // TRANSLATORS: This refers to the line tool in the tilemap editor. line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line", "Tool"), Key::L)); - line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); + line_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(line_tool_button); viewport_shortcut_buttons.push_back(line_tool_button); @@ -2254,7 +2234,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { rect_tool_button->set_toggle_mode(true); rect_tool_button->set_button_group(tool_buttons_group); rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R)); - rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); + rect_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(rect_tool_button); viewport_shortcut_buttons.push_back(rect_tool_button); @@ -2263,7 +2243,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { bucket_tool_button->set_toggle_mode(true); bucket_tool_button->set_button_group(tool_buttons_group); bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B)); - bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); + bucket_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(bucket_tool_button); toolbar->add_child(tilemap_tiles_tools_buttons); viewport_shortcut_buttons.push_back(bucket_tool_button); @@ -2305,28 +2285,28 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { transform_button_rotate_left->set_theme_type_variation("FlatButton"); transform_button_rotate_left->set_shortcut(ED_SHORTCUT("tiles_editor/rotate_tile_left", TTR("Rotate Tile Left"), Key::Z)); transform_toolbar->add_child(transform_button_rotate_left); - transform_button_rotate_left->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_LEFT)); + transform_button_rotate_left->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_LEFT)); viewport_shortcut_buttons.push_back(transform_button_rotate_left); transform_button_rotate_right = memnew(Button); transform_button_rotate_right->set_theme_type_variation("FlatButton"); transform_button_rotate_right->set_shortcut(ED_SHORTCUT("tiles_editor/rotate_tile_right", TTR("Rotate Tile Right"), Key::X)); transform_toolbar->add_child(transform_button_rotate_right); - transform_button_rotate_right->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_RIGHT)); + transform_button_rotate_right->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_RIGHT)); viewport_shortcut_buttons.push_back(transform_button_rotate_right); transform_button_flip_h = memnew(Button); transform_button_flip_h->set_theme_type_variation("FlatButton"); transform_button_flip_h->set_shortcut(ED_SHORTCUT("tiles_editor/flip_tile_horizontal", TTR("Flip Tile Horizontally"), Key::C)); transform_toolbar->add_child(transform_button_flip_h); - transform_button_flip_h->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_H)); + transform_button_flip_h->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_H)); viewport_shortcut_buttons.push_back(transform_button_flip_h); transform_button_flip_v = memnew(Button); transform_button_flip_v->set_theme_type_variation("FlatButton"); transform_button_flip_v->set_shortcut(ED_SHORTCUT("tiles_editor/flip_tile_vertical", TTR("Flip Tile Vertically"), Key::V)); transform_toolbar->add_child(transform_button_flip_v); - transform_button_flip_v->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_V)); + transform_button_flip_v->connect("pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_V)); viewport_shortcut_buttons.push_back(transform_button_flip_v); // Separator 2. @@ -2345,7 +2325,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { random_tile_toggle->set_theme_type_variation("FlatButton"); random_tile_toggle->set_toggle_mode(true); random_tile_toggle->set_tooltip_text(TTR("Place Random Tile")); - random_tile_toggle->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled)); + random_tile_toggle->connect("toggled", callable_mp(this, &TileMapLayerEditorTilesPlugin::_on_random_tile_checkbox_toggled)); tools_settings->add_child(random_tile_toggle); // Random tile scattering. @@ -2362,7 +2342,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { scatter_spinbox->set_step(0.001); scatter_spinbox->set_tooltip_text(TTR("Modifies the chance of painting nothing instead of a randomly selected tile.")); scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4); - scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed)); + scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_on_scattering_spinbox_changed)); scatter_controls_container->add_child(scatter_spinbox); tools_settings->add_child(scatter_controls_container); @@ -2377,9 +2357,9 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available. // The toolbar should be extracted to a dedicated control and theme updates should be handled through // the notification. - tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme)); - tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_stop_dragging)); - tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed)); + tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_theme)); + tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_stop_dragging)); + tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tab_changed)); tiles_bottom_panel->set_name(TTR("Tiles")); missing_source_label = memnew(Label); @@ -2412,7 +2392,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { source_sort_button->set_tooltip_text(TTR("Sort sources")); PopupMenu *p = source_sort_button->get_popup(); - p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort)); + p->connect("id_pressed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_set_source_sort)); p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorUtils::SOURCE_SORT_ID); p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorUtils::SOURCE_SORT_ID_REVERSE); p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorUtils::SOURCE_SORT_NAME); @@ -2428,13 +2408,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { sources_list->set_stretch_ratio(0.25); sources_list->set_custom_minimum_size(Size2(70, 0) * EDSCALE); sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); - sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1)); - sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_source_display).unbind(1)); + sources_list->connect("item_selected", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1)); + sources_list->connect("item_selected", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_source_display).unbind(1)); sources_list->connect("item_selected", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::set_sources_lists_current)); sources_list->connect("item_activated", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::display_tile_set_editor_panel).unbind(1)); sources_list->connect("visibility_changed", callable_mp(TilesEditorUtils::get_singleton(), &TilesEditorUtils::synchronize_sources_list).bind(sources_list, source_sort_button)); sources_list->add_user_signal(MethodInfo("sort_request")); - sources_list->connect("sort_request", callable_mp(this, &TileMapEditorTilesPlugin::_update_tile_set_sources_list)); + sources_list->connect("sort_request", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_tile_set_sources_list)); split_container_left_side->add_child(sources_list); split_container_left_side->add_child(sources_bottom_actions); @@ -2448,15 +2428,15 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { atlas_sources_split_container->add_child(tile_atlas_view); tile_atlas_control = memnew(Control); - tile_atlas_control->connect("draw", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_draw)); - tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited)); - tile_atlas_control->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_gui_input)); + tile_atlas_control->connect("draw", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_atlas_control_draw)); + tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_atlas_control_mouse_exited)); + tile_atlas_control->connect("gui_input", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_atlas_control_gui_input)); tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control); alternative_tiles_control = memnew(Control); - alternative_tiles_control->connect("draw", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_draw)); - alternative_tiles_control->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited)); - alternative_tiles_control->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input)); + alternative_tiles_control->connect("draw", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_alternatives_control_draw)); + alternative_tiles_control->connect("mouse_exited", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_alternatives_control_mouse_exited)); + alternative_tiles_control->connect("gui_input", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tile_alternatives_control_gui_input)); tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control); // Scenes collection source. @@ -2465,8 +2445,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI); - scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected)); - scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked)); + scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapLayerEditorTilesPlugin::_scenes_list_multi_selected)); + scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapLayerEditorTilesPlugin::_scenes_list_lmb_empty_clicked)); scene_tiles_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); atlas_sources_split_container->add_child(scene_tiles_list); @@ -2483,7 +2463,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { // --- Bottom panel patterns --- patterns_bottom_panel = memnew(VBoxContainer); patterns_bottom_panel->set_name(TTR("Patterns")); - patterns_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed)); + patterns_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapLayerEditorTilesPlugin::_tab_changed)); int thumbnail_size = 64; patterns_item_list = memnew(ItemList); @@ -2494,10 +2474,10 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { patterns_item_list->set_max_text_lines(2); patterns_item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - patterns_item_list->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_patterns_item_list_gui_input)); - patterns_item_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); - patterns_item_list->connect("item_activated", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); - patterns_item_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::patterns_item_list_empty_clicked)); + patterns_item_list->connect("gui_input", callable_mp(this, &TileMapLayerEditorTilesPlugin::_patterns_item_list_gui_input)); + patterns_item_list->connect("item_selected", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); + patterns_item_list->connect("item_activated", callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); + patterns_item_list->connect("empty_clicked", callable_mp(this, &TileMapLayerEditorTilesPlugin::patterns_item_list_empty_clicked)); patterns_bottom_panel->add_child(patterns_item_list); patterns_help_label = memnew(Label); @@ -2510,16 +2490,16 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { _update_source_display(); } -TileMapEditorTilesPlugin::~TileMapEditorTilesPlugin() { +TileMapLayerEditorTilesPlugin::~TileMapLayerEditorTilesPlugin() { } -void TileMapEditorTerrainsPlugin::tile_set_changed() { +void TileMapLayerEditorTerrainsPlugin::tile_set_changed() { _update_terrains_cache(); _update_terrains_tree(); _update_tiles_list(); } -void TileMapEditorTerrainsPlugin::_update_toolbar() { +void TileMapLayerEditorTerrainsPlugin::_update_toolbar() { // Hide all settings. for (int i = 0; i < tools_settings->get_child_count(); i++) { Object::cast_to<CanvasItem>(tools_settings->get_child(i))->hide(); @@ -2539,28 +2519,28 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() { } } -Vector<TileMapSubEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() const { - Vector<TileMapSubEditorPlugin::TabData> tabs; +Vector<TileMapLayerSubEditorPlugin::TabData> TileMapLayerEditorTerrainsPlugin::get_tabs() const { + Vector<TileMapLayerSubEditorPlugin::TabData> tabs; tabs.push_back({ toolbar, main_vbox_container }); return tabs; } -HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output; if (p_connect) { - terrain_fill_output = tile_map->terrain_fill_connect(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false); + terrain_fill_output = edited_layer->terrain_fill_connect(p_to_paint, p_terrain_set, p_terrain, false); } else { - terrain_fill_output = tile_map->terrain_fill_path(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false); + terrain_fill_output = edited_layer->terrain_fill_path(p_to_paint, p_terrain_set, p_terrain, false); } // Make the painted path a set for faster lookups @@ -2577,7 +2557,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_o } else { // Avoids updating the painted path from the output if the new pattern is the same as before. TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); - TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key); + TileMapCell cell = edited_layer->get_cell(kv.key); if (cell.source_id != TileSet::INVALID_SOURCE) { TileSetSource *source = *tile_set->get_source(cell.source_id); TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); @@ -2597,18 +2577,18 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_o return output; } -HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = tile_map->terrain_fill_pattern(tile_map_layer, p_to_paint, p_terrain_set, p_terrains_pattern, false); + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = edited_layer->terrain_fill_pattern(p_to_paint, p_terrain_set, p_terrains_pattern, false); // Make the painted path a set for faster lookups HashSet<Vector2i> painted_set; @@ -2624,7 +2604,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_patter } else { // Avoids updating the painted path from the output if the new pattern is the same as before. TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); - TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key); + TileMapCell cell = edited_layer->get_cell(kv.key); if (cell.source_id != TileSet::INVALID_SOURCE) { TileSetSource *source = *tile_set->get_source(cell.source_id); TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); @@ -2644,38 +2624,38 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_patter return output; } -HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } if (p_erase) { - return _draw_terrain_pattern(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, TileSet::TerrainsPattern(*tile_set, selected_terrain_set)); + return _draw_terrain_pattern(TileMapLayerEditor::get_line(edited_layer, p_start_cell, p_end_cell), selected_terrain_set, TileSet::TerrainsPattern(*tile_set, selected_terrain_set)); } else { if (selected_type == SELECTED_TYPE_CONNECT) { - return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, true); + return _draw_terrain_path_or_connect(TileMapLayerEditor::get_line(edited_layer, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, true); } else if (selected_type == SELECTED_TYPE_PATH) { - return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, false); + return _draw_terrain_path_or_connect(TileMapLayerEditor::get_line(edited_layer, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, false); } else { // SELECTED_TYPE_PATTERN - return _draw_terrain_pattern(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrains_pattern); + return _draw_terrain_pattern(TileMapLayerEditor::get_line(edited_layer, p_start_cell, p_end_cell), selected_terrain_set, selected_terrains_pattern); } } } -HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2702,18 +2682,18 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i } } -RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +RBSet<Vector2i> TileMapLayerEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return RBSet<Vector2i>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return RBSet<Vector2i>(); } - TileMapCell source_cell = tile_map->get_cell(tile_map_layer, p_coords); + TileMapCell source_cell = edited_layer->get_cell(p_coords); TileSet::TerrainsPattern source_pattern(*tile_set, selected_terrain_set); if (source_cell.source_id != TileSet::INVALID_SOURCE) { @@ -2732,7 +2712,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i // If we are filling empty tiles, compute the tilemap boundaries. Rect2i boundaries; if (source_cell.source_id == TileSet::INVALID_SOURCE) { - boundaries = tile_map->get_used_rect(); + boundaries = edited_layer->get_used_rect(); } RBSet<Vector2i> output; @@ -2747,12 +2727,12 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i if (!already_checked.has(coords)) { // Get the candidate cell pattern. TileSet::TerrainsPattern candidate_pattern(*tile_set, selected_terrain_set); - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { TileData *tile_data = nullptr; - Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords)); + Ref<TileSetSource> source = tile_set->get_source(edited_layer->get_cell_source_id(coords)); Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - tile_data = atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); + tile_data = atlas_source->get_tile_data(edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } if (tile_data) { candidate_pattern = tile_data->get_terrains_pattern(); @@ -2764,7 +2744,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i output.insert(coords); // Get surrounding tiles (handles different tile shapes). - TypedArray<Vector2i> around = tile_map->get_surrounding_cells(coords); + TypedArray<Vector2i> around = tile_set->get_surrounding_cells(coords); for (int i = 0; i < around.size(); i++) { to_check.push_back(around[i]); } @@ -2776,7 +2756,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i // Replace all tiles like the source. TypedArray<Vector2i> to_check; if (source_cell.source_id == TileSet::INVALID_SOURCE) { - Rect2i rect = tile_map->get_used_rect(); + Rect2i rect = edited_layer->get_used_rect(); if (!rect.has_area()) { rect = Rect2i(p_coords, Vector2i(1, 1)); } @@ -2786,18 +2766,18 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i } } } else { - to_check = tile_map->get_used_cells(tile_map_layer); + to_check = edited_layer->get_used_cells(); } for (int i = 0; i < to_check.size(); i++) { Vector2i coords = to_check[i]; // Get the candidate cell pattern. TileSet::TerrainsPattern candidate_pattern; - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { TileData *tile_data = nullptr; - Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords)); + Ref<TileSetSource> source = tile_set->get_source(edited_layer->get_cell_source_id(coords)); Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - tile_data = atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)); + tile_data = atlas_source->get_tile_data(edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords)); } if (tile_data) { candidate_pattern = tile_data->get_terrains_pattern(); @@ -2813,14 +2793,14 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i return output; } -HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2841,25 +2821,25 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_bucket_fill(Ve } } -void TileMapEditorTerrainsPlugin::_stop_dragging() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTerrainsPlugin::_stop_dragging() { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position()); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (drag_type) { case DRAG_TYPE_PICK: { - Vector2i coords = tile_map->local_to_map(mpos); - TileMapCell cell = tile_map->get_cell(tile_map_layer, coords); + Vector2i coords = tile_set->local_to_map(mpos); + TileMapCell cell = edited_layer->get_cell(coords); TileData *tile_data = nullptr; Ref<TileSetSource> source = tile_set->get_source(cell.source_id); @@ -2926,40 +2906,40 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() { case DRAG_TYPE_PAINT: { undo_redo->create_action(TTR("Paint terrain")); for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } undo_redo->commit_action(false); } break; case DRAG_TYPE_LINE: { - HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing); + HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos), drag_erasing); undo_redo->create_action(TTR("Paint terrain")); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); } undo_redo->commit_action(); } break; case DRAG_TYPE_RECT: { - HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing); + HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos), drag_erasing); undo_redo->create_action(TTR("Paint terrain")); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) { continue; } - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); } undo_redo->commit_action(); } break; case DRAG_TYPE_BUCKET: { undo_redo->create_action(TTR("Paint terrain")); for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key)); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + undo_redo->add_do_method(edited_layer, "set_cell", E.key, edited_layer->get_cell_source_id(E.key), edited_layer->get_cell_atlas_coords(E.key), edited_layer->get_cell_alternative_tile(E.key)); + undo_redo->add_undo_method(edited_layer, "set_cell", E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } undo_redo->commit_action(false); } break; @@ -2970,19 +2950,19 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() { drag_type = DRAG_TYPE_NONE; } -void TileMapEditorTerrainsPlugin::_mouse_exited_viewport() { +void TileMapLayerEditorTerrainsPlugin::_mouse_exited_viewport() { has_mouse = false; CanvasItemEditor::get_singleton()->update_viewport(); } -void TileMapEditorTerrainsPlugin::_update_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTerrainsPlugin::_update_selection() { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -3018,7 +2998,7 @@ void TileMapEditorTerrainsPlugin::_update_selection() { } } -bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { +bool TileMapLayerEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (!main_vbox_container->is_visible_in_tree()) { // If the bottom editor is not visible, we ignore inputs. return false; @@ -3028,21 +3008,16 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> return false; } - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return false; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return false; } - if (tile_map_layer < 0) { - return false; - } - ERR_FAIL_COND_V(tile_map_layer >= tile_map->get_layers_count(), false); - _update_selection(); Ref<InputEventKey> k = p_event; @@ -3058,18 +3033,18 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { has_mouse = true; - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(mm->get_position()); switch (drag_type) { case DRAG_TYPE_PAINT: { if (selected_terrain_set >= 0) { - HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos), drag_erasing); + HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_set->local_to_map(drag_last_mouse_pos), tile_set->local_to_map(mpos), drag_erasing); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { if (!drag_modified.has(E.key)) { - drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key); + drag_modified[E.key] = edited_layer->get_cell(E.key); } - tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } } break; @@ -3085,7 +3060,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { has_mouse = true; - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Vector2 mpos = xform.affine_inverse().xform(mb->get_position()); if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) { @@ -3108,11 +3083,11 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> drag_start_mouse_pos = mpos; drag_modified.clear(); - Vector2i cell = tile_map->local_to_map(mpos); + Vector2i cell = tile_set->local_to_map(mpos); HashMap<Vector2i, TileMapCell> to_draw = _draw_line(cell, cell, drag_erasing); for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) { - drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key); - tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + drag_modified[E.key] = edited_layer->get_cell(E.key); + edited_layer->set_cell(E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) { @@ -3135,7 +3110,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> drag_type = DRAG_TYPE_BUCKET; drag_start_mouse_pos = mpos; drag_modified.clear(); - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos)); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, tile_set->local_to_map(drag_last_mouse_pos), tile_set->local_to_map(mpos)); for (int i = 0; i < line.size(); i++) { if (!drag_modified.has(line[i])) { HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing); @@ -3145,9 +3120,9 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> } Vector2i coords = E.key; if (!drag_modified.has(coords)) { - drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords)); + drag_modified.insert(coords, edited_layer->get_cell(coords)); } - tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); + edited_layer->set_cell(coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } } } @@ -3169,28 +3144,23 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> return false; } -void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - if (tile_map_layer < 0) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count()); - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + if (!edited_layer->is_visible_in_tree()) { return; } - if (!tile_map->is_visible_in_tree()) { - return; - } - - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); - Vector2 mpos = tile_map->get_local_mouse_position(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); + Vector2 mpos = edited_layer->get_local_mouse_position(); Vector2i tile_shape_size = tile_set->get_tile_size(); // Handle the preview of the tiles to be placed. @@ -3200,10 +3170,10 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o if (drag_type == DRAG_TYPE_PICK) { // Draw the area being picked. - Vector2i coords = tile_map->local_to_map(mpos); - if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { + Vector2i coords = tile_set->local_to_map(mpos); + if (edited_layer->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) { Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(coords)); + tile_xform.set_origin(tile_set->map_to_local(coords)); tile_xform.set_scale(tile_shape_size); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false); } @@ -3211,15 +3181,15 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o bool expand_grid = false; if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) { // Preview for a single tile. - preview.insert(tile_map->local_to_map(mpos)); + preview.insert(tile_set->local_to_map(mpos)); expand_grid = true; } else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) { if (drag_type == DRAG_TYPE_NONE) { // Preview for a single tile. - preview.insert(tile_map->local_to_map(mpos)); + preview.insert(tile_set->local_to_map(mpos)); } else if (drag_type == DRAG_TYPE_LINE) { // Preview for a line. - Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos)); + Vector<Vector2i> line = TileMapLayerEditor::get_line(edited_layer, tile_set->local_to_map(drag_start_mouse_pos), tile_set->local_to_map(mpos)); for (int i = 0; i < line.size(); i++) { preview.insert(line[i]); } @@ -3228,8 +3198,8 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o } else if (drag_type == DRAG_TYPE_RECT) { // Preview for a rect. Rect2i rect; - rect.set_position(tile_map->local_to_map(drag_start_mouse_pos)); - rect.set_end(tile_map->local_to_map(mpos)); + rect.set_position(tile_set->local_to_map(drag_start_mouse_pos)); + rect.set_end(tile_set->local_to_map(mpos)); rect = rect.abs(); HashMap<Vector2i, TileSet::TerrainsPattern> to_draw; @@ -3241,7 +3211,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o expand_grid = true; } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) { // Preview for a fill. - preview = _get_cells_for_bucket_fill(tile_map->local_to_map(mpos), bucket_contiguous_checkbox->is_pressed()); + preview = _get_cells_for_bucket_fill(tile_set->local_to_map(mpos), bucket_contiguous_checkbox->is_pressed()); } // Expand the grid if needed @@ -3274,7 +3244,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y))); + tile_xform.set_origin(tile_set->map_to_local(Vector2(x, y))); tile_xform.set_scale(tile_shape_size); Color color = grid_color; color.a = color.a * opacity; @@ -3287,7 +3257,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o // Draw the preview. for (const Vector2i &E : preview) { Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(E)); + tile_xform.set_origin(tile_set->map_to_local(E)); tile_xform.set_scale(tile_set->get_tile_size()); if (drag_erasing || erase_button->is_pressed()) { tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true); @@ -3299,14 +3269,14 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o } } -void TileMapEditorTerrainsPlugin::_update_terrains_cache() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditorTerrainsPlugin::_update_terrains_cache() { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -3365,17 +3335,15 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() { } } -void TileMapEditorTerrainsPlugin::_update_terrains_tree() { +void TileMapLayerEditorTerrainsPlugin::_update_terrains_tree() { terrains_tree->clear(); terrains_tree->create_item(); - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { - return; - } + const TileMapLayer *edited_layer = _get_edited_layer(); + ERR_FAIL_NULL(edited_layer); - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -3413,16 +3381,16 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() { } } -void TileMapEditorTerrainsPlugin::_update_tiles_list() { +void TileMapLayerEditorTerrainsPlugin::_update_tiles_list() { terrains_tile_list->clear(); - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } @@ -3513,7 +3481,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() { } } -void TileMapEditorTerrainsPlugin::_update_theme() { +void TileMapLayerEditorTerrainsPlugin::_update_theme() { paint_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Edit"))); line_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Line"))); rect_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Rectangle"))); @@ -3525,27 +3493,25 @@ void TileMapEditorTerrainsPlugin::_update_theme() { _update_tiles_list(); } -void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { +void TileMapLayerEditorTerrainsPlugin::edit(ObjectID p_edited_tile_map_layer_id) { _stop_dragging(); // Avoids staying in a wrong drag state. - if (tile_map_id != p_tile_map_id) { - tile_map_id = p_tile_map_id; + if (edited_tile_map_layer_id != p_edited_tile_map_layer_id) { + edited_tile_map_layer_id = p_edited_tile_map_layer_id; // Clear the selection. _update_terrains_cache(); _update_terrains_tree(); _update_tiles_list(); } - - tile_map_layer = p_tile_map_layer; } -TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { +TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() { main_vbox_container = memnew(VBoxContainer); // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available. // The toolbar should be extracted to a dedicated control and theme updates should be handled through // the notification. - main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme)); + main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_theme)); main_vbox_container->set_name(TTR("Terrains")); HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer); @@ -3559,7 +3525,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { terrains_tree->set_custom_minimum_size(Size2(70, 0) * EDSCALE); terrains_tree->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); terrains_tree->set_hide_root(true); - terrains_tree->connect("item_selected", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_tiles_list)); + terrains_tree->connect("item_selected", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_tiles_list)); tilemap_tab_terrains->add_child(terrains_tree); terrains_tile_list = memnew(ItemList); @@ -3584,7 +3550,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { paint_tool_button->set_button_group(tool_buttons_group); paint_tool_button->set_pressed(true); paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D)); - paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar)); + paint_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(paint_tool_button); viewport_shortcut_buttons.push_back(paint_tool_button); @@ -3593,7 +3559,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { line_tool_button->set_toggle_mode(true); line_tool_button->set_button_group(tool_buttons_group); line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line"), Key::L)); - line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar)); + line_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(line_tool_button); viewport_shortcut_buttons.push_back(line_tool_button); @@ -3602,7 +3568,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { rect_tool_button->set_toggle_mode(true); rect_tool_button->set_button_group(tool_buttons_group); rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R)); - rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar)); + rect_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(rect_tool_button); viewport_shortcut_buttons.push_back(rect_tool_button); @@ -3611,7 +3577,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { bucket_tool_button->set_toggle_mode(true); bucket_tool_button->set_button_group(tool_buttons_group); bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B)); - bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar)); + bucket_tool_button->connect("pressed", callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(bucket_tool_button); viewport_shortcut_buttons.push_back(bucket_tool_button); @@ -3654,10 +3620,14 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { tools_settings->add_child(bucket_contiguous_checkbox); } -TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() { +TileMapLayerEditorTerrainsPlugin::~TileMapLayerEditorTerrainsPlugin() { } -void TileMapEditor::_notification(int p_what) { +TileMapLayer *TileMapLayerEditor::_get_edited_layer() const { + return Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id)); +} + +void TileMapLayerEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { missing_tile_texture = get_editor_theme_icon(SNAME("StatusWarning")); @@ -3671,7 +3641,8 @@ void TileMapEditor::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (is_visible_in_tree() && tileset_changed_needs_update) { _update_bottom_panel(); - _update_layers_selection(); + update_layers_selector(); + _update_highlighting_toggle(); tabs_plugins[tabs_bar->get_current_tab()]->tile_set_changed(); CanvasItemEditor::get_singleton()->update_viewport(); tileset_changed_needs_update = false; @@ -3681,79 +3652,76 @@ void TileMapEditor::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { toggle_grid_button->set_pressed(EDITOR_GET("editors/tiles_editor/display_grid")); } break; - - case NOTIFICATION_VISIBILITY_CHANGED: { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (tile_map) { - if (is_visible_in_tree()) { - tile_map->set_selected_layer(tile_map_layer); - } else { - tile_map->set_selected_layer(-1); - } - } - } break; } } -void TileMapEditor::_on_grid_toggled(bool p_pressed) { +void TileMapLayerEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("change_selected_layer_request", PropertyInfo(Variant::STRING_NAME, "layer_name"))); +} + +void TileMapLayerEditor::_on_grid_toggled(bool p_pressed) { EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed); CanvasItemEditor::get_singleton()->update_viewport(); } -void TileMapEditor::_layers_selection_item_selected(int p_index) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map || tile_map->get_layers_count() <= 0) { - return; - } +void TileMapLayerEditor::_layers_selection_item_selected(int p_index) { + emit_signal("change_selected_layer_request", layers_selection_button->get_item_metadata(p_index)); +} + +void TileMapLayerEditor::_highlight_selected_layer_button_toggled(bool p_pressed) { + TileMapLayer *edited_layer = _get_edited_layer(); + ERR_FAIL_NULL(edited_layer); - tile_map_layer = p_index; - _update_layers_selection(); + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); + ERR_FAIL_NULL(tile_map_layer_group); + + tile_map_layer_group->set_highlight_selected_layer(p_pressed); } -void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } if (p_id == 0) { // Replace Tile Proxies EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Replace Tiles with Proxies")); - for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) { - TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index); - for (int i = 0; i < used_cells.size(); i++) { - Vector2i cell_coords = used_cells[i]; - TileMapCell from = tile_map->get_cell(layer_index, cell_coords); - Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile); - TileMapCell to; - to.source_id = to_array[0]; - to.set_atlas_coords(to_array[1]); - to.alternative_tile = to_array[2]; - if (from != to) { - undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile); - undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile); - } + TypedArray<Vector2i> used_cells = edited_layer->get_used_cells(); + for (int i = 0; i < used_cells.size(); i++) { + Vector2i cell_coords = used_cells[i]; + TileMapCell from = edited_layer->get_cell(cell_coords); + Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile); + TileMapCell to; + to.source_id = to_array[0]; + to.set_atlas_coords(to_array[1]); + to.alternative_tile = to_array[2]; + if (from != to) { + undo_redo->add_do_method(edited_layer, "set_cell", cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile); + undo_redo->add_undo_method(edited_layer, "set_cell", cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile); } } + undo_redo->commit_action(); } } -void TileMapEditor::_update_bottom_panel() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditor::_update_bottom_panel() { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); + + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); // Update the visibility of controls. - missing_tileset_label->set_visible(!tile_set.is_valid()); - for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) { + missing_tileset_label->set_visible(tile_set.is_null()); + for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) { tab_data.panel->hide(); } if (tile_set.is_valid()) { @@ -3761,11 +3729,11 @@ void TileMapEditor::_update_bottom_panel() { } } -Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_cell, Vector2i p_to_cell) { - ERR_FAIL_NULL_V(p_tile_map, Vector<Vector2i>()); +Vector<Vector2i> TileMapLayerEditor::get_line(const TileMapLayer *p_tile_map_layer, Vector2i p_from_cell, Vector2i p_to_cell) { + ERR_FAIL_NULL_V(p_tile_map_layer, Vector<Vector2i>()); - Ref<TileSet> tile_set = p_tile_map->get_tileset(); - ERR_FAIL_COND_V(!tile_set.is_valid(), Vector<Vector2i>()); + Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set(); + ERR_FAIL_COND_V(tile_set.is_null(), Vector<Vector2i>()); if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) { return Geometry2D::bresenham_line(p_from_cell, p_to_cell); @@ -3775,8 +3743,8 @@ Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_ce Vector<Point2i> points; bool transposed = tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL; - p_from_cell = TileMap::transform_coords_layout(p_from_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED); - p_to_cell = TileMap::transform_coords_layout(p_to_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED); + p_from_cell = TileSet::transform_coords_layout(p_from_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED); + p_to_cell = TileSet::transform_coords_layout(p_to_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED); if (transposed) { SWAP(p_from_cell.x, p_from_cell.y); SWAP(p_to_cell.x, p_to_cell.y); @@ -3787,7 +3755,7 @@ Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_ce Vector2i sign = delta.sign(); Vector2i current = p_from_cell; - points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); + points.push_back(TileSet::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); int err = 0; if (ABS(delta.y) < ABS(delta.x)) { @@ -3805,7 +3773,7 @@ Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_ce current += Vector2i(sign.x, 0); err += err_step.y; } - points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); + points.push_back(TileSet::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); } } else { Vector2i err_step = delta.abs(); @@ -3826,7 +3794,7 @@ Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_ce } err += err_step.y; } - points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); + points.push_back(TileSet::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout())); } } @@ -3834,27 +3802,30 @@ Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_ce } } -void TileMapEditor::_tile_map_changed() { +void TileMapLayerEditor::_tile_map_layer_changed() { tileset_changed_needs_update = true; } -void TileMapEditor::_tab_changed(int p_tab_id) { +void TileMapLayerEditor::_tab_changed(int p_tab_id) { // Make the plugin edit the correct tilemap. - tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer); + tabs_plugins[tabs_bar->get_current_tab()]->edit(edited_tile_map_layer_id); // Update toolbar. - for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) { + for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) { tab_data.toolbar->hide(); } tabs_data[p_tab_id].toolbar->show(); // Update visible panel. - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) { + for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) { tab_data.panel->hide(); } - if (tile_map && tile_map->get_tileset().is_valid()) { - tabs_data[tabs_bar->get_current_tab()].panel->show(); + + TileMapLayer *tile_map_layer = _get_edited_layer(); + if (tile_map_layer) { + if (tile_map_layer->get_effective_tile_set().is_valid()) { + tabs_data[tabs_bar->get_current_tab()].panel->show(); + } } // Graphical update. @@ -3862,83 +3833,46 @@ void TileMapEditor::_tab_changed(int p_tab_id) { CanvasItemEditor::get_singleton()->update_viewport(); } -void TileMapEditor::_layers_select_next_or_previous(bool p_next) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditor::_layers_select_next_or_previous(bool p_next) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - if (tile_map->get_layers_count() < 1) { + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); + if (!tile_map_layer_group) { return; } - if (tile_map_layer < 0) { - tile_map_layer = 0; - } - int inc = p_next ? 1 : -1; - int origin_layer = tile_map_layer; - tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count()); - while (tile_map_layer != origin_layer) { - if (tile_map->is_layer_enabled(tile_map_layer)) { + int index = Math::posmod(edited_layer->get_index() + inc, tile_map_layer_group->get_child_count()); + const TileMapLayer *new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index)); + while (new_selected_layer != edited_layer) { + if (new_selected_layer && new_selected_layer->is_enabled()) { break; } - tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count()); + index = Math::posmod((index + inc), tile_map_layer_group->get_child_count()); + new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index)); } - _update_layers_selection(); + if (new_selected_layer != edited_layer) { + emit_signal("change_selected_layer_request", new_selected_layer->get_name()); + } } -void TileMapEditor::_update_layers_selection() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditor::_update_highlighting_toggle() { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - // Update the selected layer. - if (is_visible_in_tree() && tile_map->get_layers_count() >= 1) { - tile_map_layer = CLAMP(tile_map_layer, 0, tile_map->get_layers_count() - 1); - - // Search for an enabled layer if the current one is not. - int origin_layer = tile_map_layer; - while (tile_map_layer >= 0 && !tile_map->is_layer_enabled(tile_map_layer)) { - tile_map_layer--; - } - if (tile_map_layer < 0) { - tile_map_layer = origin_layer; - while (tile_map_layer < tile_map->get_layers_count() && !tile_map->is_layer_enabled(tile_map_layer)) { - tile_map_layer++; - } - } - if (tile_map_layer >= tile_map->get_layers_count()) { - tile_map_layer = -1; - } - } else { - tile_map_layer = -1; - } - tile_map->set_selected_layer(toggle_highlight_selected_layer_button->is_pressed() ? tile_map_layer : -1); - tileset_changed_needs_update = false; // Update is not needed here and actually causes problems. - - layers_selection_button->clear(); - if (tile_map->get_layers_count() > 0) { - // Build the list of layers. - for (int i = 0; i < tile_map->get_layers_count(); i++) { - String name = tile_map->get_layer_name(i); - layers_selection_button->add_item(name.is_empty() ? vformat(TTR("Layer %d"), i) : name, i); - layers_selection_button->set_item_disabled(i, !tile_map->is_layer_enabled(i)); - } - - layers_selection_button->set_disabled(false); - layers_selection_button->select(tile_map_layer); - } else { - layers_selection_button->set_disabled(true); - layers_selection_button->set_text(TTR("No Layers")); + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); + if (tile_map_layer_group) { + toggle_highlight_selected_layer_button->set_pressed(tile_map_layer_group->is_highlighting_selected_layer()); } - - tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer); } -void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { +void TileMapLayerEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); @@ -4010,7 +3944,7 @@ void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_ } } -bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { +bool TileMapLayerEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("tiles_editor/select_next_layer", p_event) && p_event->is_pressed()) { _layers_select_next_or_previous(true); return true; @@ -4024,74 +3958,71 @@ bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_gui_input(p_event); } -void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (!tile_map) { +void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { return; } - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (!tile_set.is_valid()) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_null()) { return; } - if (!tile_map->is_visible_in_tree()) { + if (!edited_layer->is_visible_in_tree()) { return; } - Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform_with_canvas(); + Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * edited_layer->get_global_transform_with_canvas(); Transform2D xform_inv = xform.affine_inverse(); Vector2i tile_shape_size = tile_set->get_tile_size(); // Draw tiles with invalid IDs in the grid. - if (tile_map_layer >= 0) { - ERR_FAIL_COND(tile_map_layer >= tile_map->get_layers_count()); - TypedArray<Vector2i> used_cells = tile_map->get_used_cells(tile_map_layer); - for (int i = 0; i < used_cells.size(); i++) { - Vector2i coords = used_cells[i]; - int tile_source_id = tile_map->get_cell_source_id(tile_map_layer, coords); - if (tile_source_id >= 0) { - Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(tile_map_layer, coords); - int tile_alternative_tile = tile_map->get_cell_alternative_tile(tile_map_layer, coords); - - TileSetSource *source = nullptr; - if (tile_set->has_source(tile_source_id)) { - source = *tile_set->get_source(tile_source_id); - } - - if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) { - // Generate a random color from the hashed values of the tiles. - Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile); - if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) { - // Only display the pattern if we have no proxy tile. - Array to_hash; - to_hash.push_back(tile_source_id); - to_hash.push_back(tile_atlas_coords); - to_hash.push_back(tile_alternative_tile); - uint32_t hash = RandomPCG(to_hash.hash()).rand(); - - Color color; - color = color.from_hsv( - (float)((hash >> 24) & 0xFF) / 256.0, - Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), - Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), - 0.8); - - // Draw the scaled tile. - Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(coords)); - tile_xform.set_scale(tile_shape_size); - tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture); - } + TypedArray<Vector2i> used_cells = edited_layer->get_used_cells(); + for (int i = 0; i < used_cells.size(); i++) { + Vector2i coords = used_cells[i]; + int tile_source_id = edited_layer->get_cell_source_id(coords); + if (tile_source_id >= 0) { + Vector2i tile_atlas_coords = edited_layer->get_cell_atlas_coords(coords); + int tile_alternative_tile = edited_layer->get_cell_alternative_tile(coords); + + TileSetSource *source = nullptr; + if (tile_set->has_source(tile_source_id)) { + source = *tile_set->get_source(tile_source_id); + } - // Draw the warning icon. - Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index(); - Vector2 icon_size; - icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3; - icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]); - Rect2 rect = Rect2(xform.xform(tile_map->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale()); - p_overlay->draw_texture_rect(missing_tile_texture, rect); + if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) { + // Generate a random color from the hashed values of the tiles. + Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile); + if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) { + // Only display the pattern if we have no proxy tile. + Array to_hash; + to_hash.push_back(tile_source_id); + to_hash.push_back(tile_atlas_coords); + to_hash.push_back(tile_alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw the scaled tile. + Transform2D tile_xform; + tile_xform.set_origin(tile_set->map_to_local(coords)); + tile_xform.set_scale(tile_shape_size); + tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture); } + + // Draw the warning icon. + Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index(); + Vector2 icon_size; + icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3; + icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]); + Rect2 rect = Rect2(xform.xform(tile_set->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale()); + p_overlay->draw_texture_rect(missing_tile_texture, rect); } } } @@ -4102,13 +4033,13 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { // Determine the drawn area. Size2 screen_size = p_overlay->get_size(); Rect2i screen_rect; - screen_rect.position = tile_map->local_to_map(xform_inv.xform(Vector2())); - screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(0, screen_size.height)))); - screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0)))); - screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(screen_size))); + screen_rect.position = tile_set->local_to_map(xform_inv.xform(Vector2())); + screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(0, screen_size.height)))); + screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0)))); + screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(screen_size))); screen_rect = screen_rect.grow(1); - Rect2i tilemap_used_rect = tile_map->get_used_rect(); + Rect2i tilemap_used_rect = edited_layer->get_used_rect(); Rect2i displayed_rect = tilemap_used_rect.intersection(screen_rect); displayed_rect = displayed_rect.grow(fading); @@ -4138,7 +4069,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); Transform2D tile_xform; - tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y))); + tile_xform.set_origin(tile_set->map_to_local(Vector2(x, y))); tile_xform.set_scale(tile_shape_size); Color color = grid_color; color.a = color.a * opacity; @@ -4151,7 +4082,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { /*Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) { for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) { - p_overlay->draw_string(font, xform.xform(tile_map->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y))); + p_overlay->draw_string(font, xform.xform(tile_set->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y))); } }*/ @@ -4159,65 +4090,100 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay); } -void TileMapEditor::edit(TileMap *p_tile_map) { - if (p_tile_map && p_tile_map->get_instance_id() == tile_map_id) { +void TileMapLayerEditor::edit(TileMapLayer *p_tile_map_layer) { + if (p_tile_map_layer && p_tile_map_layer->get_instance_id() == edited_tile_map_layer_id) { return; } - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (tile_map) { - // Unselect layer if we are changing tile_map. - if (tile_map != p_tile_map) { - tile_map->set_selected_layer(-1); - } - - // Disconnect to changes. - tile_map->disconnect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed)); + // Disconnect to changes. + TileMapLayer *tile_map_layer = _get_edited_layer(); + if (tile_map_layer) { + tile_map_layer->disconnect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); } - if (p_tile_map) { + // Update the edited layer. + if (p_tile_map_layer) { // Change the edited object. - tile_map_id = p_tile_map->get_instance_id(); - tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + edited_tile_map_layer_id = p_tile_map_layer->get_instance_id(); + + tile_map_layer = _get_edited_layer(); // Connect to changes. - if (!tile_map->is_connected("changed", callable_mp(this, &TileMapEditor::_tile_map_changed))) { - tile_map->connect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed)); + if (!tile_map_layer->is_connected("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed))) { + tile_map_layer->connect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); } } else { - tile_map_id = ObjectID(); + edited_tile_map_layer_id = ObjectID(); } - _update_layers_selection(); + update_layers_selector(); + _update_highlighting_toggle(); // Call the plugins. - tabs_plugins[tabs_bar->get_current_tab()]->edit(tile_map_id, tile_map_layer); + tabs_plugins[tabs_bar->get_current_tab()]->edit(edited_tile_map_layer_id); + + _tile_map_layer_changed(); +} + +void TileMapLayerEditor::update_layers_selector() { + const TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { + return; + } + + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); + if (tile_map_layer_group) { + // Update the selector + layers_selection_button->show(); + layers_selection_button->clear(); - _tile_map_changed(); + // Build the list of layers. + for (int i = 0; i < tile_map_layer_group->get_child_count(); i++) { + const TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(i)); + if (layer) { + int index = layers_selection_button->get_item_count(); + layers_selection_button->add_item(layer->get_name()); + layers_selection_button->set_item_disabled(index, !layer->is_enabled()); + layers_selection_button->set_item_metadata(index, layer->get_name()); + if (edited_layer == layer) { + layers_selection_button->select(index); + } + } + } + + // Disable the button if there's no layer to select. + layers_selection_button->set_disabled(false); + if (layers_selection_button->get_item_count() == 0) { + layers_selection_button->set_disabled(true); + layers_selection_button->set_text(TTR("No Layers")); + } + } else { + layers_selection_button->hide(); + } } -TileMapEditor::TileMapEditor() { +TileMapLayerEditor::TileMapLayerEditor() { set_process_internal(true); // Shortcuts. - ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), Key::PAGEUP); - ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), Key::PAGEDOWN); + ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), Key::PAGEDOWN); + ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), Key::PAGEUP); // TileMap editor plugins - tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin)); - tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin)); + tile_map_editor_plugins.push_back(memnew(TileMapLayerEditorTilesPlugin)); + tile_map_editor_plugins.push_back(memnew(TileMapLayerEditorTerrainsPlugin)); // TabBar. tabs_bar = memnew(TabBar); tabs_bar->set_clip_tabs(false); for (int plugin_index = 0; plugin_index < tile_map_editor_plugins.size(); plugin_index++) { - Vector<TileMapSubEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs(); + Vector<TileMapLayerSubEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs(); for (int tab_index = 0; tab_index < tabs_vector.size(); tab_index++) { tabs_bar->add_tab(tabs_vector[tab_index].panel->get_name()); tabs_data.push_back(tabs_vector[tab_index]); tabs_plugins.push_back(tile_map_editor_plugins[plugin_index]); } } - tabs_bar->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed)); + tabs_bar->connect("tab_changed", callable_mp(this, &TileMapLayerEditor::_tab_changed)); // --- TileMap toolbar --- tile_map_toolbar = memnew(HFlowContainer); @@ -4228,7 +4194,7 @@ TileMapEditor::TileMapEditor() { tile_map_toolbar->add_child(tabs_bar); // Tabs toolbars. - for (TileMapSubEditorPlugin::TabData &tab_data : tabs_data) { + for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) { tab_data.toolbar->hide(); if (!tab_data.toolbar->get_parent()) { tile_map_toolbar->add_child(tab_data.toolbar); @@ -4246,14 +4212,14 @@ TileMapEditor::TileMapEditor() { layers_selection_button->set_custom_minimum_size(Size2(200, 0)); layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); layers_selection_button->set_tooltip_text(TTR("TileMap Layers")); - layers_selection_button->connect("item_selected", callable_mp(this, &TileMapEditor::_layers_selection_item_selected)); + layers_selection_button->connect("item_selected", callable_mp(this, &TileMapLayerEditor::_layers_selection_item_selected)); tile_map_toolbar->add_child(layers_selection_button); toggle_highlight_selected_layer_button = memnew(Button); toggle_highlight_selected_layer_button->set_theme_type_variation("FlatButton"); toggle_highlight_selected_layer_button->set_toggle_mode(true); toggle_highlight_selected_layer_button->set_pressed(true); - toggle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection)); + toggle_highlight_selected_layer_button->connect("toggled", callable_mp(this, &TileMapLayerEditor::_highlight_selected_layer_button_toggled)); toggle_highlight_selected_layer_button->set_tooltip_text(TTR("Highlight Selected TileMap Layer")); tile_map_toolbar->add_child(toggle_highlight_selected_layer_button); @@ -4264,7 +4230,7 @@ TileMapEditor::TileMapEditor() { toggle_grid_button->set_theme_type_variation("FlatButton"); toggle_grid_button->set_toggle_mode(true); toggle_grid_button->set_tooltip_text(TTR("Toggle grid visibility.")); - toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled)); + toggle_grid_button->connect("toggled", callable_mp(this, &TileMapLayerEditor::_on_grid_toggled)); tile_map_toolbar->add_child(toggle_grid_button); // Advanced settings menu button. @@ -4272,7 +4238,7 @@ TileMapEditor::TileMapEditor() { advanced_menu_button->set_flat(false); advanced_menu_button->set_theme_type_variation("FlatButton"); advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies")); - advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapEditor::_advanced_menu_button_id_pressed)); + advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapLayerEditor::_advanced_menu_button_id_pressed)); tile_map_toolbar->add_child(advanced_menu_button); missing_tileset_label = memnew(Label); @@ -4294,10 +4260,10 @@ TileMapEditor::TileMapEditor() { _tab_changed(0); // Registers UndoRedo inspector callback. - EditorNode::get_editor_data().add_move_array_element_function(SNAME("TileMap"), callable_mp(this, &TileMapEditor::_move_tile_map_array_element)); + EditorNode::get_editor_data().add_move_array_element_function(SNAME("TileMap"), callable_mp(this, &TileMapLayerEditor::_move_tile_map_array_element)); } -TileMapEditor::~TileMapEditor() { +TileMapLayerEditor::~TileMapLayerEditor() { for (int i = 0; i < tile_map_editor_plugins.size(); i++) { memdelete(tile_map_editor_plugins[i]); } diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_layer_editor.h index c9a1efe62d..2a01a3c17a 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_layer_editor.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* tile_map_editor.h */ +/* tile_map_layer_editor.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TILE_MAP_EDITOR_H -#define TILE_MAP_EDITOR_H +#ifndef TILE_MAP_LAYER_EDITOR_H +#define TILE_MAP_LAYER_EDITOR_H #include "tile_atlas_view.h" @@ -48,9 +48,13 @@ #include "scene/gui/tab_bar.h" #include "scene/gui/tree.h" -class TileMapEditor; +class TileMapLayerEditor; + +class TileMapLayerSubEditorPlugin : public Object { +protected: + ObjectID edited_tile_map_layer_id; + TileMapLayer *_get_edited_layer() const; -class TileMapSubEditorPlugin : public Object { public: struct TabData { Control *toolbar = nullptr; @@ -64,11 +68,11 @@ public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; }; virtual void forward_canvas_draw_over_viewport(Control *p_overlay){}; virtual void tile_set_changed(){}; - virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer){}; + virtual void edit(ObjectID p_tile_map_layer_id){}; }; -class TileMapEditorTilesPlugin : public TileMapSubEditorPlugin { - GDCLASS(TileMapEditorTilesPlugin, TileMapSubEditorPlugin); +class TileMapLayerEditorTilesPlugin : public TileMapLayerSubEditorPlugin { + GDCLASS(TileMapLayerEditorTilesPlugin, TileMapLayerSubEditorPlugin); public: enum { @@ -79,10 +83,6 @@ public: }; private: - ObjectID tile_map_id; - int tile_map_layer = -1; - virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; - ///// Toolbar ///// HBoxContainer *toolbar = nullptr; @@ -237,18 +237,16 @@ public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override; virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override; - TileMapEditorTilesPlugin(); - ~TileMapEditorTilesPlugin(); + virtual void edit(ObjectID p_tile_map_layer_id) override; + + TileMapLayerEditorTilesPlugin(); + ~TileMapLayerEditorTilesPlugin(); }; -class TileMapEditorTerrainsPlugin : public TileMapSubEditorPlugin { - GDCLASS(TileMapEditorTerrainsPlugin, TileMapSubEditorPlugin); +class TileMapLayerEditorTerrainsPlugin : public TileMapLayerSubEditorPlugin { + GDCLASS(TileMapLayerEditorTerrainsPlugin, TileMapLayerSubEditorPlugin); private: - ObjectID tile_map_id; - int tile_map_layer = -1; - virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; - // Toolbar. HBoxContainer *toolbar = nullptr; @@ -331,28 +329,33 @@ public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override; virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override; - TileMapEditorTerrainsPlugin(); - ~TileMapEditorTerrainsPlugin(); + virtual void edit(ObjectID p_tile_map_layer_id) override; + + TileMapLayerEditorTerrainsPlugin(); + ~TileMapLayerEditorTerrainsPlugin(); }; -class TileMapEditor : public VBoxContainer { - GDCLASS(TileMapEditor, VBoxContainer); +class TileMapLayerEditor : public VBoxContainer { + GDCLASS(TileMapLayerEditor, VBoxContainer); private: bool tileset_changed_needs_update = false; - ObjectID tile_map_id; - int tile_map_layer = -1; + + ObjectID edited_tile_map_layer_id; + TileMapLayer *_get_edited_layer() const; // Vector to keep plugins. - Vector<TileMapSubEditorPlugin *> tile_map_editor_plugins; + Vector<TileMapLayerSubEditorPlugin *> tile_map_editor_plugins; // Toolbar. HFlowContainer *tile_map_toolbar = nullptr; OptionButton *layers_selection_button = nullptr; - Button *toggle_highlight_selected_layer_button = nullptr; void _layers_selection_item_selected(int p_index); + Button *toggle_highlight_selected_layer_button = nullptr; + void _highlight_selected_layer_button_toggled(bool p_pressed); + Button *toggle_grid_button = nullptr; void _on_grid_toggled(bool p_pressed); @@ -362,8 +365,8 @@ private: // Bottom panel. Label *missing_tileset_label = nullptr; TabBar *tabs_bar = nullptr; - LocalVector<TileMapSubEditorPlugin::TabData> tabs_data; - LocalVector<TileMapSubEditorPlugin *> tabs_plugins; + LocalVector<TileMapLayerSubEditorPlugin::TabData> tabs_data; + LocalVector<TileMapLayerSubEditorPlugin *> tabs_plugins; void _update_bottom_panel(); // TileMap. @@ -371,31 +374,33 @@ private: Ref<Texture2D> warning_pattern_texture; // CallBack. - void _tile_map_changed(); + void _tile_map_layer_changed(); void _tab_changed(int p_tab_changed); // Updates. void _layers_select_next_or_previous(bool p_next); - void _update_layers_selection(); + void _update_highlighting_toggle(); // Inspector undo/redo callback. void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos); protected: void _notification(int p_what); + static void _bind_methods(); void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color); public: bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); - void edit(TileMap *p_tile_map); + void edit(TileMapLayer *p_tile_map_layer); + void update_layers_selector(); - TileMapEditor(); - ~TileMapEditor(); + TileMapLayerEditor(); + ~TileMapLayerEditor(); // Static functions. - static Vector<Vector2i> get_line(TileMap *p_tile_map, Vector2i p_from_cell, Vector2i p_to_cell); + static Vector<Vector2i> get_line(const TileMapLayer *p_tile_map_layer, Vector2i p_from_cell, Vector2i p_to_cell); }; -#endif // TILE_MAP_EDITOR_H +#endif // TILE_MAP_LAYER_EDITOR_H diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 65f52bc92c..8ef052c71f 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -40,8 +40,8 @@ #include "editor/editor_string_names.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/themes/editor_scale.h" - #include "scene/2d/tile_map.h" +#include "scene/2d/tile_map_layer.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/control.h" @@ -324,7 +324,7 @@ TilesEditorUtils::~TilesEditorUtils() { singleton = nullptr; } -void TileMapEditorPlugin::_tile_map_changed() { +void TileMapEditorPlugin::_tile_map_layer_changed() { if (tile_map_changed_needs_update) { return; } @@ -332,23 +332,105 @@ void TileMapEditorPlugin::_tile_map_changed() { callable_mp(this, &TileMapEditorPlugin::_update_tile_map).call_deferred(); } -void TileMapEditorPlugin::_update_tile_map() { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); +void TileMapEditorPlugin::_tile_map_layer_removed() { + // Workaround for TileMap, making sure the editor stays open when you delete the currently edited layer. + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_group_id)); if (tile_map) { - Ref<TileSet> tile_set = tile_map->get_tileset(); - if (tile_set.is_valid() && edited_tileset != tile_set->get_instance_id()) { - tile_set_plugin_singleton->edit(tile_map->get_tileset().ptr()); + edit(tile_map); + } +} + +void TileMapEditorPlugin::_update_tile_map() { + TileMapLayer *edited_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(tile_map_layer_id)); + if (edited_layer) { + Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + if (tile_set.is_valid() && tile_set_id != tile_set->get_instance_id()) { + tile_set_plugin_singleton->edit(tile_set.ptr()); tile_set_plugin_singleton->make_visible(true); - edited_tileset = tile_set->get_instance_id(); + tile_set_id = tile_set->get_instance_id(); } else if (tile_set.is_null()) { tile_set_plugin_singleton->edit(nullptr); tile_set_plugin_singleton->make_visible(false); - edited_tileset = ObjectID(); + tile_set_id = ObjectID(); } } tile_map_changed_needs_update = false; } +void TileMapEditorPlugin::_select_layer(const StringName &p_name) { + TileMapLayer *edited_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(tile_map_layer_id)); + ERR_FAIL_NULL(edited_layer); + + Node *parent = edited_layer->get_parent(); + ERR_FAIL_NULL(parent); + + TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(parent->get_node_or_null(String(p_name))); + edit(new_layer); +} + +void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer) { + ERR_FAIL_NULL(p_tile_map_layer); + + editor->edit(p_tile_map_layer); + + // Update the selected layers in the TileMapLayerGroup parent node. + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(p_tile_map_layer->get_parent()); + if (tile_map_layer_group) { + Vector<StringName> selected; + selected.push_back(p_tile_map_layer->get_name()); + tile_map_layer_group->set_selected_layers(selected); + } + + // Update the object IDs. + tile_map_layer_id = p_tile_map_layer->get_instance_id(); + p_tile_map_layer->connect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_changed)); + p_tile_map_layer->connect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed)); + if (tile_map_layer_group) { + tile_map_group_id = tile_map_layer_group->get_instance_id(); + tile_map_layer_group->connect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); + tile_map_layer_group->connect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); + tile_map_layer_group->connect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector)); + } + + // Update the edited tileset. + Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set(); + if (tile_set.is_valid()) { + tile_set_plugin_singleton->edit(tile_set.ptr()); + tile_set_plugin_singleton->make_visible(true); + tile_set_id = tile_set->get_instance_id(); + } else { + tile_set_plugin_singleton->edit(nullptr); + tile_set_plugin_singleton->make_visible(false); + } +} + +void TileMapEditorPlugin::_edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group) { + ERR_FAIL_NULL(p_tile_map_layer_group); + + Vector<StringName> selected_layers = p_tile_map_layer_group->get_selected_layers(); + + TileMapLayer *selected_layer = nullptr; + if (selected_layers.size() > 0) { + // Edit the selected layer. + selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_node_or_null(String(selected_layers[0]))); + } + if (!selected_layer) { + // Edit the first layer found. + for (int i = 0; i < p_tile_map_layer_group->get_child_count(); i++) { + selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_child(i)); + if (selected_layer) { + break; + } + } + } + + if (selected_layer) { + _edit_tile_map_layer(selected_layer); + } else { + editor->edit(nullptr); + } +} + void TileMapEditorPlugin::_notification(int p_notification) { if (p_notification == NOTIFICATION_EXIT_TREE) { get_tree()->queue_delete(TilesEditorUtils::get_singleton()); @@ -356,39 +438,42 @@ void TileMapEditorPlugin::_notification(int p_notification) { } void TileMapEditorPlugin::edit(Object *p_object) { - TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); - if (tile_map) { - tile_map->disconnect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_changed)); + TileMapLayer *edited_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(tile_map_layer_id)); + if (edited_layer) { + edited_layer->disconnect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_changed)); + edited_layer->disconnect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed)); } - tile_map = Object::cast_to<TileMap>(p_object); - if (tile_map) { - tile_map_id = tile_map->get_instance_id(); - } else { - tile_map_id = ObjectID(); + TileMapLayerGroup *tile_map_group = Object::cast_to<TileMapLayerGroup>(ObjectDB::get_instance(tile_map_group_id)); + if (tile_map_group) { + tile_map_group->disconnect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); + tile_map_group->disconnect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); + tile_map_group->disconnect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector)); } - editor->edit(tile_map); - if (tile_map) { - tile_map->connect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_changed)); + tile_map_group_id = ObjectID(); + tile_map_layer_id = ObjectID(); + tile_set_id = ObjectID(); - if (tile_map->get_tileset().is_valid()) { - tile_set_plugin_singleton->edit(tile_map->get_tileset().ptr()); - tile_set_plugin_singleton->make_visible(true); - edited_tileset = tile_map->get_tileset()->get_instance_id(); - } - } else if (edited_tileset.is_valid()) { - // Hide the TileSet editor, unless another TileSet is being edited. - if (tile_set_plugin_singleton->get_edited_tileset() == edited_tileset) { - tile_set_plugin_singleton->edit(nullptr); - tile_set_plugin_singleton->make_visible(false); + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMap>(p_object); + TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_object); + if (tile_map_layer_group) { + _edit_tile_map_layer_group(tile_map_layer_group); + } else if (tile_map_layer) { + _edit_tile_map_layer(tile_map_layer); + } else { + // Deselect the layer in the group. + if (edited_layer) { + tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); + if (tile_map_layer_group) { + tile_map_layer_group->set_selected_layers(Vector<StringName>()); + } } - edited_tileset = ObjectID(); } } bool TileMapEditorPlugin::handles(Object *p_object) const { - return Object::cast_to<TileMap>(p_object) != nullptr; + return Object::cast_to<TileMapLayer>(p_object) != nullptr || Object::cast_to<TileMapLayerGroup>(p_object) != nullptr; } void TileMapEditorPlugin::make_visible(bool p_visible) { @@ -427,10 +512,11 @@ TileMapEditorPlugin::TileMapEditorPlugin() { } tile_map_plugin_singleton = this; - editor = memnew(TileMapEditor); + editor = memnew(TileMapLayerEditor); editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); + editor->connect("change_selected_layer_request", callable_mp(this, &TileMapEditorPlugin::_select_layer)); editor->hide(); button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileMap"), editor); diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h index 6ca115454a..ac3e8986d6 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.h +++ b/editor/plugins/tiles/tiles_editor_plugin.h @@ -35,7 +35,7 @@ #include "scene/gui/box_container.h" #include "tile_atlas_view.h" -#include "tile_map_editor.h" +#include "tile_map_layer_editor.h" #include "tile_set_editor.h" class TilesEditorUtils : public Object { @@ -113,15 +113,21 @@ public: class TileMapEditorPlugin : public EditorPlugin { GDCLASS(TileMapEditorPlugin, EditorPlugin); - TileMapEditor *editor = nullptr; + TileMapLayerEditor *editor = nullptr; Button *button = nullptr; - ObjectID tile_map_id; + ObjectID tile_map_layer_id; + ObjectID tile_map_group_id; // Allow keeping the layer selector up to date. bool tile_map_changed_needs_update = false; - ObjectID edited_tileset; // The TileSet associated with the TileMap. + ObjectID tile_set_id; // The TileSet associated with the TileMap. - void _tile_map_changed(); + void _tile_map_layer_changed(); + void _tile_map_layer_removed(); void _update_tile_map(); + void _select_layer(const StringName &p_name); + + void _edit_tile_map_layer(TileMapLayer *p_tile_map_layer); + void _edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group); protected: void _notification(int p_notification); diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 9b1aacc2e9..88622364d8 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -104,3 +104,12 @@ Validate extension JSON: Error: Field 'classes/GLTFBufferView/methods/get_byte_s Validate extension JSON: Error: Field 'classes/GLTFBufferView/methods/get_indices': is_const changed value in new API, from false to true. Change AudioStreamPlayer* is_autoplay_enabled and GLTFBufferView getters to be const. + + +GH-87379 +-------- +Validate extension JSON: API was removed: classes/TileMap/methods/get_tileset +Validate extension JSON: API was removed: classes/TileMap/methods/set_tileset +Validate extension JSON: API was removed: classes/TileMap/properties/tile_set + +Moved to the parent TileMapLayerGroup class. No change should be necessary. diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index f40ee1f506..4cbcfa6dc2 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -49,131 +49,8 @@ ERR_FAIL_INDEX_V(layer, (int)layers.size(), err_value); \ return layers[layer]->function(__VA_ARGS__); -Vector2i TileMap::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) { - // Transform to stacked layout. - Vector2i output = p_coords; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - SWAP(output.x, output.y); - } - switch (p_from_layout) { - case TileSet::TILE_LAYOUT_STACKED: - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - if (output.y % 2) { - output.x -= 1; - } - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if (output.y < 0 && bool(output.y % 2)) { - output = Vector2i(output.x + output.y / 2 - 1, output.y); - } else { - output = Vector2i(output.x + output.y / 2, output.y); - } - } else { - if (output.x < 0 && bool(output.x % 2)) { - output = Vector2i(output.x / 2 - 1, output.x + output.y * 2); - } else { - output = Vector2i(output.x / 2, output.x + output.y * 2); - } - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if ((output.x + output.y) < 0 && (output.x - output.y) % 2) { - output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x); - } else { - output = Vector2i((output.x + output.y) / 2, -output.x + output.y); - } - } else { - if ((output.x - output.y) < 0 && (output.x + output.y) % 2) { - output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y); - } else { - output = Vector2i((output.x - output.y) / 2, output.x + output.y); - } - } - break; - } - - switch (p_to_layout) { - case TileSet::TILE_LAYOUT_STACKED: - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - if (output.y % 2) { - output.x += 1; - } - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if (output.y < 0 && (output.y % 2)) { - output = Vector2i(output.x - output.y / 2 + 1, output.y); - } else { - output = Vector2i(output.x - output.y / 2, output.y); - } - } else { - if (output.y % 2) { - if (output.y < 0) { - output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1); - } else { - output = Vector2i(2 * output.x + 1, -output.x + output.y / 2); - } - } else { - output = Vector2i(2 * output.x, -output.x + output.y / 2); - } - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if (output.y % 2) { - if (output.y > 0) { - output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1); - } else { - output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2); - } - } else { - output = Vector2i(output.x - output.y / 2, output.x + output.y / 2); - } - } else { - if (output.y % 2) { - if (output.y < 0) { - output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1); - } else { - output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2); - } - } else { - output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2); - } - } - break; - } - - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - SWAP(output.x, output.y); - } - - return output; -} - -void TileMap::set_selected_layer(int p_layer_id) { - ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size()); - if (selected_layer == p_layer_id) { - return; - } - selected_layer = p_layer_id; +void TileMap::_emit_changed() { emit_signal(CoreStringNames::get_singleton()->changed); - - // Update the layers modulation. - for (TileMapLayer *layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER); - } -} - -int TileMap::get_selected_layer() const { - return selected_layer; } void TileMap::_notification(int p_what) { @@ -188,7 +65,6 @@ void TileMap::_notification(int p_what) { if (is_inside_tree() && collision_animatable && !in_editor) { // Update transform on the physics tick when in animatable mode. last_valid_transform = new_transform; - print_line("Physics: ", new_transform); set_notify_local_transform(false); set_global_transform(new_transform); set_notify_local_transform(true); @@ -207,7 +83,6 @@ void TileMap::_notification(int p_what) { // Store last valid transform. new_transform = get_global_transform(); - print_line("local XFORM: ", last_valid_transform); // ... but then revert changes. set_notify_local_transform(false); set_global_transform(last_valid_transform); @@ -225,55 +100,6 @@ void TileMap::force_update(int p_layer) { } #endif -void TileMap::queue_internal_update() { - if (pending_update) { - return; - } - pending_update = true; - callable_mp(this, &TileMap::_internal_update).call_deferred(); -} - -void TileMap::_internal_update() { - // Other updates. - if (!pending_update) { - return; - } - - // Update dirty quadrants on layers. - for (TileMapLayer *layer : layers) { - layer->internal_update(); - } - - pending_update = false; -} - -void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { - if (p_tileset == tile_set) { - return; - } - - // Set the tileset, registering to its changes. - if (tile_set.is_valid()) { - tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed)); - } - - tile_set = p_tileset; - - if (tile_set.is_valid()) { - tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed)); - } - - for (TileMapLayer *layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET); - } - - emit_signal(CoreStringNames::get_singleton()->changed); -} - -Ref<TileSet> TileMap::get_tileset() const { - return tile_set; -} - void TileMap::set_rendering_quadrant_size(int p_size) { ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1."); @@ -281,7 +107,7 @@ void TileMap::set_rendering_quadrant_size(int p_size) { for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE); } - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); } int TileMap::get_rendering_quadrant_size() const { @@ -392,10 +218,11 @@ void TileMap::add_layer(int p_to_pos) { for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_layer_index_in_tile_map_node(i); } - queue_internal_update(); + new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); + notify_property_list_changed(); - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); update_configuration_warnings(); } @@ -412,14 +239,9 @@ void TileMap::move_layer(int p_layer, int p_to_pos) { move_child(layer, i); layers[i]->set_layer_index_in_tile_map_node(i); } - queue_internal_update(); notify_property_list_changed(); - if (selected_layer == p_layer) { - selected_layer = p_to_pos < p_layer ? p_to_pos - 1 : p_to_pos; - } - - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); update_configuration_warnings(); } @@ -433,14 +255,9 @@ void TileMap::remove_layer(int p_layer) { for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_layer_index_in_tile_map_node(i); } - queue_internal_update(); notify_property_list_changed(); - if (selected_layer >= p_layer) { - selected_layer -= 1; - } - - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); update_configuration_warnings(); } @@ -533,7 +350,7 @@ void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_colli for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE); } - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); } TileMap::VisibilityMode TileMap::get_collision_visibility_mode() const { @@ -548,7 +365,7 @@ void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navi for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE); } - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); } TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() const { @@ -563,7 +380,7 @@ void TileMap::set_y_sort_enabled(bool p_enable) { for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED); } - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); update_configuration_warnings(); } @@ -671,8 +488,9 @@ void TileMap::clear() { } void TileMap::update_internals() { - pending_update = true; - _internal_update(); + for (TileMapLayer *layer : layers) { + layer->update_internals(); + } } void TileMap::notify_runtime_tile_data_update(int p_layer) { @@ -721,10 +539,11 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { add_child(new_layer); new_layer->set_name("Layer0"); new_layer->set_layer_index_in_tile_map_node(0); + new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); } layers[0]->set_tile_data(format, p_value); - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); return true; } return false; @@ -745,11 +564,12 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { add_child(new_layer); new_layer->set_name(vformat("Layer%d", index)); new_layer->set_layer_index_in_tile_map_node(index); + new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); } notify_property_list_changed(); - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); update_configuration_warnings(); } @@ -776,7 +596,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { return true; } else if (components[1] == "tile_data") { layers[index]->set_tile_data(format, p_value); - emit_signal(CoreStringNames::get_singleton()->changed); + _emit_changed(); return true; } else { return false; @@ -1014,93 +834,12 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { } } -TypedArray<Vector2i> TileMap::get_surrounding_cells(const Vector2i &coords) { +TypedArray<Vector2i> TileMap::get_surrounding_cells(const Vector2i &p_coords) { if (!tile_set.is_valid()) { return TypedArray<Vector2i>(); } - TypedArray<Vector2i> around; - TileSet::TileShape shape = tile_set->get_tile_shape(); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE)); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); - } else { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); - } else { - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE)); - around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); - } - } - - return around; -} - -void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform) { - if (!tile_set.is_valid()) { - return; - } - - // Create a set. - Vector2i tile_size = tile_set->get_tile_size(); - Vector<Vector2> polygon = tile_set->get_tile_shape_polygon(); - TileSet::TileShape shape = tile_set->get_tile_shape(); - - for (const Vector2i &E : p_cells) { - Vector2 center = map_to_local(E); - -#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \ - if (!p_cells.has(get_neighbor_cell(E, side))) { \ - Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \ - Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \ - p_control->draw_line(from, to, p_color); \ - } - - if (shape == TileSet::TILE_SHAPE_SQUARE) { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0); - } else { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5); - } else { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); - } - } - } -#undef DRAW_SIDE_IF_NEEDED + return tile_set->get_surrounding_cells(p_coords); } Array TileMap::get_configuration_warnings() const { @@ -1171,9 +910,6 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1)); #endif // DISABLE_DEPRECATED - ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset); - ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset); - ClassDB::bind_method(D_METHOD("set_rendering_quadrant_size", "size"), &TileMap::set_rendering_quadrant_size); ClassDB::bind_method(D_METHOD("get_rendering_quadrant_size"), &TileMap::get_rendering_quadrant_size); @@ -1244,7 +980,6 @@ void TileMap::_bind_methods() { GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords"); GDVIRTUAL_BIND(_tile_data_runtime_update, "layer", "coords", "tile_data"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rendering_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_rendering_quadrant_size", "get_rendering_quadrant_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode"); @@ -1261,28 +996,18 @@ void TileMap::_bind_methods() { BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_SHOW); } -void TileMap::_tile_set_changed() { - emit_signal(CoreStringNames::get_singleton()->changed); - for (TileMapLayer *layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET); - } - update_configuration_warnings(); -} - TileMap::TileMap() { TileMapLayer *new_layer = memnew(TileMapLayer); add_child(new_layer); new_layer->set_name("Layer0"); new_layer->set_layer_index_in_tile_map_node(0); + new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); default_layer = memnew(TileMapLayer); } TileMap::~TileMap() { - if (tile_set.is_valid()) { - tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed)); - } memdelete(default_layer); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 22efbf018f..9e66dd4dd9 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -31,7 +31,7 @@ #ifndef TILE_MAP_H #define TILE_MAP_H -#include "scene/2d/node_2d.h" +#include "scene/2d/tile_map_layer_group.h" #include "scene/resources/tile_set.h" class Control; @@ -45,8 +45,8 @@ enum TileMapDataFormat { FORMAT_MAX, }; -class TileMap : public Node2D { - GDCLASS(TileMap, Node2D); +class TileMap : public TileMapLayerGroup { + GDCLASS(TileMap, TileMapLayerGroup); public: enum VisibilityMode { @@ -64,7 +64,6 @@ private: static constexpr float FP_ADJUST = 0.00001; // Properties. - Ref<TileSet> tile_set; int rendering_quadrant_size = 16; bool collision_animatable = false; VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT; @@ -73,14 +72,12 @@ private: // Layers. LocalVector<TileMapLayer *> layers; TileMapLayer *default_layer; // Dummy layer to fetch default values. - int selected_layer = -1; - bool pending_update = false; // Transforms for collision_animatable. Transform2D last_valid_transform; Transform2D new_transform; - void _tile_set_changed(); + void _emit_changed(); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -103,8 +100,6 @@ protected: #endif public: - static Vector2i transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout); - #ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const override; #endif @@ -113,13 +108,6 @@ public: void force_update(int p_layer); #endif - // Called by TileMapLayers. - void queue_internal_update(); - void _internal_update(); - - void set_tileset(const Ref<TileSet> &p_tileset); - Ref<TileSet> get_tileset() const; - void set_rendering_quadrant_size(int p_size); int get_rendering_quadrant_size() const; @@ -148,9 +136,6 @@ public: void set_layer_navigation_map(int p_layer, RID p_map); RID get_layer_navigation_map(int p_layer) const; - void set_selected_layer(int p_layer_id); // For editor use. - int get_selected_layer() const; - void set_collision_animatable(bool p_collision_animatable); bool is_collision_animatable() const; @@ -224,8 +209,7 @@ public: void notify_runtime_tile_data_update(int p_layer = -1); // Helpers? - TypedArray<Vector2i> get_surrounding_cells(const Vector2i &coords); - void draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform = Transform2D()); + TypedArray<Vector2i> get_surrounding_cells(const Vector2i &p_coords); // Virtual function to modify the TileData at runtime. GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i); diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index df79b3fee6..0888852de5 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -44,14 +44,6 @@ TileMap *TileMapLayer::_fetch_tilemap() const { return TileMap::cast_to<TileMap>(get_parent()); } -Ref<TileSet> TileMapLayer::_fetch_tileset() const { - TileMap *tile_map_node = _fetch_tilemap(); - if (!tile_map_node) { - return Ref<TileSet>(); - } - return tile_map_node->get_tileset(); -} - #ifdef DEBUG_ENABLED /////////////////////////////// Debug ////////////////////////////////////////// constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16; @@ -63,7 +55,7 @@ Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords } void TileMapLayer::_debug_update() { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. @@ -192,7 +184,7 @@ void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList< /////////////////////////////// Rendering ////////////////////////////////////// void TileMapLayer::_rendering_update() { const TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. @@ -206,17 +198,22 @@ void TileMapLayer::_rendering_update() { // Modulate the layer. Color layer_modulate = get_modulate(); - int selected_layer = tile_map_node->get_selected_layer(); - if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) { - int z_selected = tile_map_node->get_layer_z_index(selected_layer); - int layer_z_index = get_z_index(); - if (layer_z_index < z_selected || (layer_z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) { - layer_modulate = layer_modulate.darkened(0.5); - } else if (layer_z_index > z_selected || (layer_z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) { - layer_modulate = layer_modulate.darkened(0.5); - layer_modulate.a *= 0.3; +#ifdef TOOLS_ENABLED + const Vector<StringName> selected_layers = tile_map_node->get_selected_layers(); + if (tile_map_node->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) { + TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_node->get_node_or_null(String(selected_layers[0]))); + if (selected_layer) { + int z_selected = selected_layer->get_z_index(); + int layer_z_index = get_z_index(); + if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) { + layer_modulate = layer_modulate.darkened(0.5); + } else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) { + layer_modulate = layer_modulate.darkened(0.5); + layer_modulate.a *= 0.3; + } } } +#endif // TOOLS_ENABLED rs->canvas_item_set_modulate(get_canvas_item(), layer_modulate); } @@ -228,7 +225,7 @@ void TileMapLayer::_rendering_update() { // Check if anything changed that might change the quadrant shape. // If so, recreate everything. bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] || - (is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET])); + (is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET])); // Free all quadrants. if (forced_cleanup || quandrant_shape_changed) { @@ -247,7 +244,7 @@ void TileMapLayer::_rendering_update() { if (!forced_cleanup) { // List all quadrants to update, recreating them if needed. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || _rendering_was_cleaned_up) { + if (dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || _rendering_was_cleaned_up) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { CellData &cell_data = kv.value; @@ -427,7 +424,7 @@ void TileMapLayer::_rendering_update() { _rendering_occluders_clear_cell(kv.value); } } else { - if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _rendering_occluders_update_cell(kv.value); @@ -448,7 +445,7 @@ void TileMapLayer::_rendering_update() { void TileMapLayer::_rendering_notification(int p_what) { RenderingServer *rs = RenderingServer::get_singleton(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_what == NOTIFICATION_TRANSFORM_CHANGED || p_what == NOTIFICATION_ENTER_CANVAS || p_what == NOTIFICATION_VISIBILITY_CHANGED) { if (tile_set.is_valid()) { Transform2D tilemap_xform = get_global_transform(); @@ -469,7 +466,7 @@ void TileMapLayer::_rendering_notification(int p_what) { void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) { const TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); // Check if the cell is valid and retrieve its y_sort_origin. bool is_valid = false; @@ -569,7 +566,7 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Free unused occluders then resize the occluders array. @@ -638,7 +635,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(!tile_set.is_valid()); if (!Engine::get_singleton()->is_editor_hint()) { @@ -687,7 +684,7 @@ void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Ve /////////////////////////////// Physics ////////////////////////////////////// void TileMapLayer::_physics_update() { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); // Check if we should cleanup everything. bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); @@ -697,7 +694,7 @@ void TileMapLayer::_physics_update() { _physics_clear_cell(kv.value); } } else { - if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { + if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _physics_update_cell(kv.value); @@ -717,7 +714,7 @@ void TileMapLayer::_physics_update() { } void TileMapLayer::_physics_notification(int p_what) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); Transform2D gl_transform = get_global_transform(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -771,7 +768,7 @@ void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) { void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { const TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); Transform2D gl_transform = get_global_transform(); RID space = get_world_2d()->get_space(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -889,7 +886,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { // Draw the debug collision shapes. TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(!tile_set.is_valid()); if (!get_tree()) { @@ -945,7 +942,7 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect void TileMapLayer::_navigation_update() { ERR_FAIL_NULL(NavigationServer2D::get_singleton()); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); NavigationServer2D *ns = NavigationServer2D::get_singleton(); // Check if we should cleanup everything. @@ -982,7 +979,7 @@ void TileMapLayer::_navigation_update() { _navigation_clear_cell(kv.value); } } else { - if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { + if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _navigation_update_cell(kv.value); @@ -1002,7 +999,7 @@ void TileMapLayer::_navigation_update() { } void TileMapLayer::_navigation_notification(int p_what) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { if (tile_set.is_valid()) { Transform2D tilemap_xform = get_global_transform(); @@ -1037,7 +1034,7 @@ void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { const TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); NavigationServer2D *ns = NavigationServer2D::get_singleton(); Transform2D gl_xform = get_global_transform(); @@ -1136,7 +1133,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V return; } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); @@ -1222,7 +1219,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V /////////////////////////////// Scenes ////////////////////////////////////// void TileMapLayer::_scenes_update() { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); // Check if we should cleanup everything. bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); @@ -1233,7 +1230,7 @@ void TileMapLayer::_scenes_update() { _scenes_clear_cell(kv.value); } } else { - if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { + if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _scenes_update_cell(kv.value); @@ -1268,7 +1265,7 @@ void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); // Clear the scene in any case. _scenes_clear_cell(r_cell_data); @@ -1305,7 +1302,7 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(!tile_set.is_valid()); if (!Engine::get_singleton()->is_editor_hint()) { @@ -1356,13 +1353,13 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto void TileMapLayer::_build_runtime_update_tile_data() { const TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); // Check if we should cleanup everything. bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); if (!forced_cleanup) { if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) { - if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) { for (KeyValue<Vector2i, CellData> &E : tile_map) { _build_runtime_update_tile_data_for_cell(E.value); } @@ -1386,7 +1383,7 @@ void TileMapLayer::_build_runtime_update_tile_data() { void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) { TileMap *tile_map_node = _fetch_tilemap(); - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); TileMapCell &c = r_cell_data.cell; TileSetSource *source; @@ -1428,8 +1425,8 @@ void TileMapLayer::_clear_runtime_update_tile_data() { } } -TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) { - const Ref<TileSet> &tile_set = _fetch_tileset(); +TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) const { + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (!tile_set.is_valid()) { return TileSet::TerrainsPattern(); } @@ -1490,7 +1487,7 @@ TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } @@ -1511,7 +1508,7 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_patte } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } @@ -1599,8 +1596,7 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cel } void TileMapLayer::_renamed() { - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringNames::get_singleton()->changed); } void TileMapLayer::_update_notify_local_transform() { @@ -1614,6 +1610,66 @@ void TileMapLayer::_update_notify_local_transform() { set_notify_local_transform(notify); } +void TileMapLayer::_queue_internal_update() { + if (pending_update) { + return; + } + pending_update = true; + callable_mp(this, &TileMapLayer::_deferred_internal_update).call_deferred(); +} + +void TileMapLayer::_deferred_internal_update() { + // Other updates. + if (!pending_update) { + return; + } + + // Update dirty quadrants on layers. + _internal_update(); + + pending_update = false; +} + +void TileMapLayer::_internal_update() { + // Find TileData that need a runtime modification. + // This may add cells to the dirty list is a runtime modification has been notified. + _build_runtime_update_tile_data(); + + // Update all subsystems. + _rendering_update(); + _physics_update(); + _navigation_update(); + _scenes_update(); +#ifdef DEBUG_ENABLED + _debug_update(); +#endif // DEBUG_ENABLED + + _clear_runtime_update_tile_data(); + + // Clear the "what is dirty" flags. + for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { + dirty.flags[i] = false; + } + + // List the cells to delete definitely. + Vector<Vector2i> to_delete; + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + // Select the the cell from tile_map if it is invalid. + if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) { + to_delete.push_back(cell_data.coords); + } + } + + // Remove cells that are empty after the cleanup. + for (const Vector2i &coords : to_delete) { + tile_map.erase(coords); + } + + // Clear the dirty cells list. + dirty.cell_list.clear(); +} + void TileMapLayer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_POSTINITIALIZE: { @@ -1623,32 +1679,27 @@ void TileMapLayer::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { _update_notify_local_transform(); dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); + _queue_internal_update(); } break; case NOTIFICATION_EXIT_TREE: { dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); + _queue_internal_update(); } break; case TileMap::NOTIFICATION_ENTER_CANVAS: { dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); + _queue_internal_update(); } break; case TileMap::NOTIFICATION_EXIT_CANVAS: { dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); + _queue_internal_update(); } break; case TileMap::NOTIFICATION_VISIBILITY_CHANGED: { dirty.flags[DIRTY_FLAGS_LAYER_VISIBILITY] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); + _queue_internal_update(); } break; } @@ -1657,18 +1708,23 @@ void TileMapLayer::_notification(int p_what) { _navigation_notification(p_what); } +void TileMapLayer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); + + ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); +} + void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) { if (p_index == layer_index_in_tile_map_node) { return; } - TileMap *tile_map_node = _fetch_tilemap(); layer_index_in_tile_map_node = p_index; dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true; - tile_map_node->queue_internal_update(); + _queue_internal_update(); } Rect2 TileMapLayer::get_rect(bool &r_changed) const { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (tile_set.is_null()) { r_changed = rect_cache != Rect2(); return Rect2(); @@ -1702,8 +1758,8 @@ Rect2 TileMapLayer::get_rect(bool &r_changed) const { return rect_cache; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) { - const Ref<TileSet> &tile_set = _fetch_tileset(); +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) const { + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (!tile_set.is_valid()) { return HashMap<Vector2i, TileSet::TerrainsPattern>(); } @@ -1750,9 +1806,9 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constrain return output; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1856,9 +1912,9 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c return output; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1930,9 +1986,9 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons return output; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1988,7 +2044,7 @@ TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) return TileMapCell(); } else { TileMapCell c = tile_map.find(p_coords)->value.cell; - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile); c.source_id = proxyed[0]; @@ -2064,7 +2120,7 @@ void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> & coord_y = decode_uint16(&local[10]); } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (tile_set.is_valid()) { Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); if (a.size() == 3) { @@ -2105,49 +2161,19 @@ Vector<int> TileMapLayer::get_tile_data() const { } void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) { - TileMap *tile_map_node = _fetch_tilemap(); - dirty.flags[p_what] = true; - tile_map_node->queue_internal_update(); -} - -void TileMapLayer::internal_update() { - // Find TileData that need a runtime modification. - // This may add cells to the dirty list is a runtime modification has been notified. - _build_runtime_update_tile_data(); - - // Update all subsystems. - _rendering_update(); - _physics_update(); - _navigation_update(); - _scenes_update(); -#ifdef DEBUG_ENABLED - _debug_update(); -#endif // DEBUG_ENABLED - - _clear_runtime_update_tile_data(); - - // Clear the "what is dirty" flags. - for (int i = 0; i < DIRTY_FLAGS_MAX; i++) { - dirty.flags[i] = false; + if (p_what == DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS || + p_what == DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED || + p_what == DIRTY_FLAGS_LAYER_GROUP_TILE_SET) { + emit_signal(CoreStringNames::get_singleton()->changed); } - // List the cells to delete definitely. - Vector<Vector2i> to_delete; - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - // Select the the cell from tile_map if it is invalid. - if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) { - to_delete.push_back(cell_data.coords); - } - } - - // Remove cells that are empty after the cleanup. - for (const Vector2i &coords : to_delete) { - tile_map.erase(coords); - } + dirty.flags[p_what] = true; + _queue_internal_update(); +} - // Clear the dirty cells list. - dirty.cell_list.clear(); +void TileMapLayer::update_internals() { + pending_update = true; + _deferred_internal_update(); } void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) { @@ -2190,10 +2216,7 @@ void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vec if (!E->value.dirty_list_element.in_list()) { dirty.cell_list.add(&(E->value.dirty_list_element)); } - TileMap *tile_map_node = _fetch_tilemap(); - if (tile_map_node) { // Needed to avoid crashes in destructor. - tile_map_node->queue_internal_update(); - } + _queue_internal_update(); used_rect_cache_dirty = true; } @@ -2210,7 +2233,7 @@ int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxie return TileSet::INVALID_SOURCE; } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[0]; @@ -2227,7 +2250,7 @@ Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_us return TileSetSource::INVALID_ATLAS_COORDS; } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[1]; @@ -2244,7 +2267,7 @@ int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use return TileSetSource::INVALID_TILE_ALTERNATIVE; } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[2]; @@ -2259,7 +2282,7 @@ TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_ return nullptr; } - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); if (source.is_valid()) { return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies)); @@ -2277,7 +2300,7 @@ void TileMapLayer::clear() { } Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); Ref<TileMapPattern> output; @@ -2331,7 +2354,7 @@ Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_arra } void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(tile_set.is_null()); ERR_FAIL_COND(p_pattern.is_null()); @@ -2343,7 +2366,7 @@ void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPatt } void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(!tile_set.is_valid()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); @@ -2383,7 +2406,7 @@ void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p } void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = _fetch_tileset(); + const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(!tile_set.is_valid()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); @@ -2490,10 +2513,10 @@ void TileMapLayer::set_enabled(bool p_enabled) { } enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->update_configuration_warnings(); } @@ -2507,9 +2530,8 @@ void TileMapLayer::set_self_modulate(const Color &p_self_modulate) { } CanvasItem::set_self_modulate(p_self_modulate); dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { @@ -2518,10 +2540,10 @@ void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { } CanvasItem::set_y_sort_enabled(p_y_sort_enabled); dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->update_configuration_warnings(); _update_notify_local_transform(); } @@ -2532,9 +2554,8 @@ void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { } y_sort_origin = p_y_sort_origin; dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } int TileMapLayer::get_y_sort_origin() const { @@ -2547,19 +2568,18 @@ void TileMapLayer::set_z_index(int p_z_index) { } CanvasItem::set_z_index(p_z_index); dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->update_configuration_warnings(); } void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) { use_kinematic_bodies = p_use_kinematic_bodies; dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] = p_use_kinematic_bodies; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } bool TileMapLayer::is_using_kinematic_bodies() const { @@ -2572,9 +2592,8 @@ void TileMapLayer::set_navigation_enabled(bool p_enabled) { } navigation_enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED] = true; - TileMap *tile_map_node = _fetch_tilemap(); - tile_map_node->queue_internal_update(); - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } bool TileMapLayer::is_navigation_enabled() const { @@ -2595,7 +2614,7 @@ RID TileMapLayer::get_navigation_map() const { } void TileMapLayer::fix_invalid_tiles() { - Ref<TileSet> tileset = _fetch_tileset(); + Ref<TileSet> tileset = get_effective_tile_set(); ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); RBSet<Vector2i> coords; @@ -2618,6 +2637,15 @@ Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { return bodies_coords[p_physics_body]; } +Ref<TileSet> TileMapLayer::get_effective_tile_set() const { + TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(get_parent()); + if (tile_map_layer_group) { + return tile_map_layer_group->get_tileset(); + } else { + return Ref<TileSet>(); + } +} + TileMapLayer::TileMapLayer() { set_notify_transform(true); } @@ -2625,7 +2653,7 @@ TileMapLayer::TileMapLayer() { TileMapLayer::~TileMapLayer() { in_destructor = true; clear(); - internal_update(); + _internal_update(); } HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coords_and_peering_bits() const { diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index 2cc57f50d1..6cf432bc24 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -232,13 +232,15 @@ public: DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED, DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE, - DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER, + DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS, + DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED, + DIRTY_FLAGS_LAYER_GROUP_TILE_SET, + DIRTY_FLAGS_TILE_MAP_LIGHT_MASK, DIRTY_FLAGS_TILE_MAP_MATERIAL, DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL, DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER, DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT, - DIRTY_FLAGS_TILE_MAP_TILE_SET, DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE, DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE, DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE, @@ -259,6 +261,7 @@ private: // Internal. int layer_index_in_tile_map_node = -1; HashMap<Vector2i, CellData> tile_map; + bool pending_update = false; // Dirty flag. Allows knowing what was modified since the last update. struct { @@ -275,7 +278,6 @@ private: // Method to fetch the TileSet to use TileMap *_fetch_tilemap() const; - Ref<TileSet> _fetch_tileset() const; // Runtime tile data. bool _runtime_update_tile_data_was_cleaned_up = false; @@ -331,15 +333,21 @@ private: #endif // DEBUG_ENABLED // Terrains. - TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern); + TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) const; RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; void _renamed(); void _update_notify_local_transform(); + // Internal updates. + void _queue_internal_update(); + void _deferred_internal_update(); + void _internal_update(); + protected: void _notification(int p_what); + static void _bind_methods(); public: // TileMap node. @@ -349,10 +357,10 @@ public: Rect2 get_rect(bool &r_changed) const; // Terrains. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) const; // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true) const; // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true) const; // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true) const; // Not exposed. // Not exposed to users. TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const; @@ -361,10 +369,10 @@ public: void set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data); Vector<int> get_tile_data() const; void notify_tile_map_change(DirtyFlags p_what); - void internal_update(); - // --- Exposed in TileMap --- + void update_internals(); + // --- Exposed in TileMap --- // Cells manipulation. void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); void erase_cell(const Vector2i &p_coords); @@ -410,6 +418,11 @@ public: bool has_body_rid(RID p_physics_body) const; Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. + // Helper. + Ref<TileSet> get_effective_tile_set() const; + + // --- + TileMapLayer(); ~TileMapLayer(); }; diff --git a/scene/2d/tile_map_layer_group.cpp b/scene/2d/tile_map_layer_group.cpp new file mode 100644 index 0000000000..ac0de380a3 --- /dev/null +++ b/scene/2d/tile_map_layer_group.cpp @@ -0,0 +1,148 @@ +/**************************************************************************/ +/* tile_map_layer_group.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "tile_map_layer_group.h" + +#include "core/core_string_names.h" +#include "scene/2d/tile_map_layer.h" +#include "scene/resources/tile_set.h" + +#ifdef TOOLS_ENABLED + +void TileMapLayerGroup::_cleanup_selected_layers() { + for (int i = 0; i < selected_layers.size(); i++) { + const String name = selected_layers[i]; + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_node_or_null(name)); + if (!layer) { + selected_layers.remove_at(i); + i--; + } + } +} + +#endif // TOOLS_ENABLED + +void TileMapLayerGroup::_tile_set_changed() { + for (int i = 0; i < get_child_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); + if (layer) { + layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET); + } + } + + update_configuration_warnings(); +} + +#ifdef TOOLS_ENABLED + +void TileMapLayerGroup::set_selected_layers(Vector<StringName> p_layer_names) { + selected_layers = p_layer_names; + _cleanup_selected_layers(); + + // Update the layers modulation. + for (int i = 0; i < get_child_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); + if (layer) { + layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS); + } + } +} + +Vector<StringName> TileMapLayerGroup::get_selected_layers() const { + return selected_layers; +} + +void TileMapLayerGroup::set_highlight_selected_layer(bool p_highlight_selected_layer) { + if (highlight_selected_layer == p_highlight_selected_layer) { + return; + } + + highlight_selected_layer = p_highlight_selected_layer; + + for (int i = 0; i < get_child_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); + if (layer) { + layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED); + } + } +} + +bool TileMapLayerGroup::is_highlighting_selected_layer() const { + return highlight_selected_layer; +} + +#endif // TOOLS_ENABLED + +void TileMapLayerGroup::remove_child_notify(Node *p_child) { +#ifdef TOOLS_ENABLED + _cleanup_selected_layers(); +#endif // TOOLS_ENABLED +} + +void TileMapLayerGroup::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMapLayerGroup::set_tileset); + ClassDB::bind_method(D_METHOD("get_tileset"), &TileMapLayerGroup::get_tileset); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); +} + +void TileMapLayerGroup::set_tileset(const Ref<TileSet> &p_tileset) { + if (p_tileset == tile_set) { + return; + } + + // Set the tileset, registering to its changes. + if (tile_set.is_valid()) { + tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); + } + + tile_set = p_tileset; + + if (tile_set.is_valid()) { + tile_set->connect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); + } + + for (int i = 0; i < get_child_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); + if (layer) { + layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET); + } + } +} + +Ref<TileSet> TileMapLayerGroup::get_tileset() const { + return tile_set; +} + +TileMapLayerGroup::~TileMapLayerGroup() { + if (tile_set.is_valid()) { + tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); + } +} diff --git a/scene/2d/tile_map_layer_group.h b/scene/2d/tile_map_layer_group.h new file mode 100644 index 0000000000..d80c244f80 --- /dev/null +++ b/scene/2d/tile_map_layer_group.h @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* tile_map_layer_group.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TILE_MAP_LAYER_GROUP_H +#define TILE_MAP_LAYER_GROUP_H + +#include "scene/2d/node_2d.h" + +class TileSet; + +class TileMapLayerGroup : public Node2D { + GDCLASS(TileMapLayerGroup, Node2D); + +private: + mutable Vector<StringName> selected_layers; + bool highlight_selected_layer = true; + +#ifdef TOOLS_ENABLED + void _cleanup_selected_layers(); +#endif + void _tile_set_changed(); + +protected: + Ref<TileSet> tile_set; + + virtual void remove_child_notify(Node *p_child) override; + + static void _bind_methods(); + +public: +#ifdef TOOLS_ENABLED + // For editor use. + void set_selected_layers(Vector<StringName> p_layer_names); + Vector<StringName> get_selected_layers() const; + void set_highlight_selected_layer(bool p_highlight_selected_layer); + bool is_highlighting_selected_layer() const; +#endif + + // Accessors. + void set_tileset(const Ref<TileSet> &p_tileset); + Ref<TileSet> get_tileset() const; + + ~TileMapLayerGroup(); +}; + +#endif // TILE_MAP_LAYER_GROUP_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 64a1c72f9d..c7d044caf2 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -783,6 +783,7 @@ void register_scene_types() { GDREGISTER_CLASS(TileMapPattern); GDREGISTER_CLASS(TileData); GDREGISTER_CLASS(TileMap); + GDREGISTER_ABSTRACT_CLASS(TileMapLayerGroup); GDREGISTER_CLASS(ParallaxBackground); GDREGISTER_CLASS(ParallaxLayer); GDREGISTER_CLASS(TouchScreenButton); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 66e1b7bcf9..96891f2480 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1478,7 +1478,7 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti ERR_FAIL_V(TileMapCell()); } -Vector<Vector2> TileSet::get_tile_shape_polygon() { +Vector<Vector2> TileSet::get_tile_shape_polygon() const { Vector<Vector2> points; if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { points.push_back(Vector2(-0.5, -0.5)); @@ -1519,7 +1519,7 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() { return points; } -void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { +void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) const { if (tile_meshes_dirty) { Vector<Vector2> shape = get_tile_shape_polygon(); Vector<Vector2> uvs; @@ -2165,7 +2165,40 @@ Vector2i TileSet::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeigh } } -Vector2i TileSet::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { +TypedArray<Vector2i> TileSet::get_surrounding_cells(const Vector2i &p_coords) const { + TypedArray<Vector2i> around; + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_SIDE)); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); + } else { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); + } else { + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_SIDE)); + around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)); + } + } + + return around; +} + +Vector2i TileSet::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) const { ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i()); ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i()); @@ -2189,6 +2222,49 @@ Vector2i TileSet::map_pattern(const Vector2i &p_position_in_tilemap, const Vecto return output; } +void TileSet::draw_cells_outline(CanvasItem *p_canvas_item, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform) const { + Vector<Vector2> polygon = get_tile_shape_polygon(); + for (const Vector2i &E : p_cells) { + Vector2 center = map_to_local(E); + +#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \ + if (!p_cells.has(get_neighbor_cell(E, side))) { \ + Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \ + Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \ + p_canvas_item->draw_line(from, to, p_color); \ + } + + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0); + } else { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5); + } else { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); + } + } + } +#undef DRAW_SIDE_IF_NEEDED +} + Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) { if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { return _get_square_terrain_polygon(tile_size); @@ -3185,6 +3261,115 @@ void TileSet::reset_state() { tile_size = Size2i(16, 16); } +Vector2i TileSet::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) { + // Transform to stacked layout. + Vector2i output = p_coords; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + SWAP(output.x, output.y); + } + switch (p_from_layout) { + case TileSet::TILE_LAYOUT_STACKED: + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + if (output.y % 2) { + output.x -= 1; + } + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if (output.y < 0 && bool(output.y % 2)) { + output = Vector2i(output.x + output.y / 2 - 1, output.y); + } else { + output = Vector2i(output.x + output.y / 2, output.y); + } + } else { + if (output.x < 0 && bool(output.x % 2)) { + output = Vector2i(output.x / 2 - 1, output.x + output.y * 2); + } else { + output = Vector2i(output.x / 2, output.x + output.y * 2); + } + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if ((output.x + output.y) < 0 && (output.x - output.y) % 2) { + output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x); + } else { + output = Vector2i((output.x + output.y) / 2, -output.x + output.y); + } + } else { + if ((output.x - output.y) < 0 && (output.x + output.y) % 2) { + output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y); + } else { + output = Vector2i((output.x - output.y) / 2, output.x + output.y); + } + } + break; + } + + switch (p_to_layout) { + case TileSet::TILE_LAYOUT_STACKED: + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + if (output.y % 2) { + output.x += 1; + } + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if (output.y < 0 && (output.y % 2)) { + output = Vector2i(output.x - output.y / 2 + 1, output.y); + } else { + output = Vector2i(output.x - output.y / 2, output.y); + } + } else { + if (output.y % 2) { + if (output.y < 0) { + output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1); + } else { + output = Vector2i(2 * output.x + 1, -output.x + output.y / 2); + } + } else { + output = Vector2i(2 * output.x, -output.x + output.y / 2); + } + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if (output.y % 2) { + if (output.y > 0) { + output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1); + } else { + output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2); + } + } else { + output = Vector2i(output.x - output.y / 2, output.x + output.y / 2); + } + } else { + if (output.y % 2) { + if (output.y < 0) { + output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1); + } else { + output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2); + } + } else { + output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2); + } + } + break; + } + + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + SWAP(output.x, output.y); + } + + return output; +} + const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1); const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1; diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 0a6d879047..f26ed461c3 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -319,7 +319,7 @@ private: Ref<ArrayMesh> tile_lines_mesh; Ref<ArrayMesh> tile_filled_mesh; - bool tile_meshes_dirty = true; + mutable bool tile_meshes_dirty = true; // Physics struct PhysicsLayer { @@ -527,15 +527,17 @@ public: TileMapCell get_random_tile_from_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern); // Helpers - Vector<Vector2> get_tile_shape_polygon(); - void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); + Vector<Vector2> get_tile_shape_polygon() const; + void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()) const; // Used by TileMap/TileMapLayer Vector2 map_to_local(const Vector2i &p_pos) const; Vector2i local_to_map(const Vector2 &p_pos) const; bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const; Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; - Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern); + TypedArray<Vector2i> get_surrounding_cells(const Vector2i &p_coords) const; + Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) const; + void draw_cells_outline(CanvasItem *p_canvas_item, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform = Transform2D()) const; Vector<Point2> get_terrain_polygon(int p_terrain_set); Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); @@ -545,6 +547,9 @@ public: // Resource management virtual void reset_state() override; + // Helpers. + static Vector2i transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout); + TileSet(); ~TileSet(); }; |