From 33be8b07017455149f8be3e9b6adf14fc9b9a829 Mon Sep 17 00:00:00 2001 From: Mariano Suligoy Date: Thu, 28 Feb 2019 20:48:34 -0300 Subject: Allow to change selection around all tiles on the texture without clicking on them. Fixes #25203. Fixes #22077 --- editor/plugins/tile_set_editor_plugin.cpp | 184 ++++++++++++++++++++++++++++++ editor/plugins/tile_set_editor_plugin.h | 8 ++ 2 files changed, 192 insertions(+) (limited to 'editor/plugins') diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 5f4c4a610a..8bcec00a67 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -201,6 +201,7 @@ void TileSetEditor::_bind_methods() { ClassDB::bind_method("_zoom_out", &TileSetEditor::_zoom_out); ClassDB::bind_method("_zoom_reset", &TileSetEditor::_zoom_reset); ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord); + ClassDB::bind_method("_sort_tiles", &TileSetEditor::_sort_tiles); ClassDB::bind_method("edit", &TileSetEditor::edit); ClassDB::bind_method("add_texture", &TileSetEditor::add_texture); @@ -233,6 +234,8 @@ void TileSetEditor::_notification(int p_what) { tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons")); tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); tools[SHAPE_NEW_RECTANGLE]->set_icon(get_icon("CollisionShape2D", "EditorIcons")); + tools[SELECT_PREVIOUS]->set_icon(get_icon("ArrowLeft", "EditorIcons")); + tools[SELECT_NEXT]->set_icon(get_icon("ArrowRight", "EditorIcons")); tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); @@ -323,11 +326,29 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", varray(i)); tool_hb->add_child(tool_workspacemode[i]); } + Control *spacer = memnew(Control); spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); tool_hb->add_child(spacer); tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE); + tools[SELECT_NEXT] = memnew(ToolButton); + tool_hb->add_child(tools[SELECT_NEXT]); + tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE); + tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Select next coordinate"), KEY_PAGEDOWN)); + tools[SELECT_NEXT]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_NEXT)); + tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile.")); + tools[SELECT_PREVIOUS] = memnew(ToolButton); + tool_hb->add_child(tools[SELECT_PREVIOUS]); + tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE); + tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Select previous coordinate"), KEY_PAGEUP)); + tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile.")); + tools[SELECT_PREVIOUS]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_PREVIOUS)); + + VSeparator *separator_shape_selection = memnew(VSeparator); + tool_hb->add_child(separator_shape_selection); + tool_hb->move_child(separator_shape_selection, WORKSPACE_CREATE_SINGLE); + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); workspace_mode = WORKSPACE_EDIT; @@ -1490,6 +1511,10 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->add_do_method(workspace, "update"); undo_redo->add_undo_method(workspace, "update"); undo_redo->commit_action(); + } else if (p_tool == SELECT_NEXT) { + _select_next_subtile(); + } else if (p_tool == SELECT_PREVIOUS) { + _select_previous_subtile(); } else if (p_tool == SHAPE_DELETE) { if (creating_shape) { creating_shape = false; @@ -1604,6 +1629,165 @@ void TileSetEditor::_on_grid_snap_toggled(bool p_val) { workspace->update(); } +void TileSetEditor::_select_next_tile() { + Array tiles = _get_tiles_in_current_texture(true); + if (tiles.size() == 0) { + set_current_tile(-1); + } else if (get_current_tile() == -1) { + set_current_tile(tiles[0]); + } else { + int index = tiles.find(get_current_tile()); + if (index < 0) { + set_current_tile(tiles[0]); + } else if (index == tiles.size() - 1) { + set_current_tile(tiles[0]); + } else { + set_current_tile(tiles[index + 1]); + } + } + if (get_current_tile() == -1) { + return; + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + return; + } else { + switch (edit_mode) { + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: + case EDITMODE_Z_INDEX: { + edited_shape_coord = Vector2(); + _select_edited_shape_coord(); + } break; + default: {} + } + } +} + +void TileSetEditor::_select_previous_tile() { + Array tiles = _get_tiles_in_current_texture(true); + if (tiles.size() == 0) { + set_current_tile(-1); + } else if (get_current_tile() == -1) { + set_current_tile(tiles[tiles.size() - 1]); + } else { + int index = tiles.find(get_current_tile()); + if (index <= 0) { + set_current_tile(tiles[tiles.size() - 1]); + } else { + set_current_tile(tiles[index - 1]); + } + } + if (get_current_tile() == -1) { + return; + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + return; + } else { + switch (edit_mode) { + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: + case EDITMODE_Z_INDEX: { + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + cell_count -= Vector2(1, 1); + edited_shape_coord = cell_count; + _select_edited_shape_coord(); + } break; + default: {} + } + } +} + +Array TileSetEditor::_get_tiles_in_current_texture(bool sorted) { + Array a; + List all_tiles; + if (!get_current_texture().is_valid()) { + return a; + } + tileset->get_tile_list(&all_tiles); + for (int i = 0; i < all_tiles.size(); i++) { + if (tileset->tile_get_texture(all_tiles[i]) == get_current_texture()) { + a.push_back(all_tiles[i]); + } + } + if (sorted) { + a.sort_custom(this, "_sort_tiles"); + } + return a; +} + +bool TileSetEditor::_sort_tiles(Variant p_a, Variant p_b) { + int a = p_a; + int b = p_b; + + Vector2 pos_a = tileset->tile_get_region(a).position; + Vector2 pos_b = tileset->tile_get_region(b).position; + if (pos_a.y < pos_b.y) { + return true; + + } else if (pos_a.y == pos_b.y) { + if (pos_a.x < pos_b.x) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +void TileSetEditor::_select_next_subtile() { + if (get_current_tile() == -1) { + _select_next_tile(); + return; + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + _select_next_tile(); + } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { + _select_next_tile(); + } else { + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) { + _select_next_tile(); + } else { + edited_shape_coord.x++; + if (edited_shape_coord.x >= cell_count.x) { + edited_shape_coord.x = 0; + edited_shape_coord.y++; + } + _select_edited_shape_coord(); + } + } +} + +void TileSetEditor::_select_previous_subtile() { + if (get_current_tile() == -1) { + _select_previous_tile(); + return; + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + _select_previous_tile(); + } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { + _select_previous_tile(); + } else { + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) { + _select_previous_tile(); + } else { + edited_shape_coord.x--; + if (edited_shape_coord.x == -1) { + edited_shape_coord.x = cell_count.x - 1; + edited_shape_coord.y--; + } + _select_edited_shape_coord(); + } + } +} + void TileSetEditor::_set_snap_step(Vector2 p_val) { snap_step.x = CLAMP(p_val.x, 0, 256); snap_step.y = CLAMP(p_val.y, 0, 256); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 6bbfee8714..c9a1123618 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -76,6 +76,8 @@ class TileSetEditor : public HSplitContainer { }; enum TileSetTools { + SELECT_PREVIOUS, + SELECT_NEXT, TOOL_SELECT, BITMASK_COPY, BITMASK_PASTE, @@ -188,6 +190,12 @@ private: void _on_priority_changed(float val); void _on_z_index_changed(float val); void _on_grid_snap_toggled(bool p_val); + void _select_next_tile(); + void _select_previous_tile(); + Array _get_tiles_in_current_texture(bool sorted = false); + bool _sort_tiles(Variant p_a, Variant p_b); + void _select_next_subtile(); + void _select_previous_subtile(); void _set_snap_step(Vector2 p_val); void _set_snap_off(Vector2 p_val); void _set_snap_sep(Vector2 p_val); -- cgit v1.2.3 From 65084a70fd786a37b0c58ce01ec3fef2391aeefe Mon Sep 17 00:00:00 2001 From: Mariano Suligoy Date: Thu, 28 Feb 2019 22:45:16 -0300 Subject: Allow to change selection of collision shapes added to the same tile. Fixes #26369. --- editor/plugins/tile_set_editor_plugin.cpp | 157 ++++++++++++++++++++++++++++-- editor/plugins/tile_set_editor_plugin.h | 10 ++ 2 files changed, 161 insertions(+), 6 deletions(-) (limited to 'editor/plugins') diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 8bcec00a67..26ee6a9f83 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1512,9 +1512,9 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->add_undo_method(workspace, "update"); undo_redo->commit_action(); } else if (p_tool == SELECT_NEXT) { - _select_next_subtile(); + _select_next_shape(); } else if (p_tool == SELECT_PREVIOUS) { - _select_previous_subtile(); + _select_previous_shape(); } else if (p_tool == SHAPE_DELETE) { if (creating_shape) { creating_shape = false; @@ -1629,6 +1629,41 @@ void TileSetEditor::_on_grid_snap_toggled(bool p_val) { workspace->update(); } +void TileSetEditor::_update_tile_data() { + current_tile_data.clear(); + if (get_current_tile() < 0) + return; + + Vector sd = tileset->tile_get_shapes(get_current_tile()); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + SubtileData data; + for (int i = 0; i < sd.size(); i++) { + data.collisions.push_back(sd[i].shape); + } + data.navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); + data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); + current_tile_data[Vector2i()] = data; + } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); + for (int y = 0; y < cell_count.y; y++) { + for (int x = 0; x < cell_count.x; x++) { + SubtileData data; + Vector2i coord(x, y); + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + data.collisions.push_back(sd[i].shape); + } + } + data.navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord); + data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); + current_tile_data[coord] = data; + } + } + } +} + void TileSetEditor::_select_next_tile() { Array tiles = _get_tiles_in_current_texture(true); if (tiles.size() == 0) { @@ -1689,8 +1724,9 @@ void TileSetEditor::_select_previous_tile() { case EDITMODE_NAVIGATION: case EDITMODE_PRIORITY: case EDITMODE_Z_INDEX: { + int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->tile_get_region(get_current_tile()).size; - Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); cell_count -= Vector2(1, 1); edited_shape_coord = cell_count; _select_edited_shape_coord(); @@ -1748,8 +1784,9 @@ void TileSetEditor::_select_next_subtile() { } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { _select_next_tile(); } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->tile_get_region(get_current_tile()).size; - Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) { _select_next_tile(); } else { @@ -1773,8 +1810,9 @@ void TileSetEditor::_select_previous_subtile() { } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { _select_previous_tile(); } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->tile_get_region(get_current_tile()).size; - Vector2i cell_count = size / tileset->autotile_get_size(get_current_tile()); + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) { _select_previous_tile(); } else { @@ -1788,6 +1826,112 @@ void TileSetEditor::_select_previous_subtile() { } } +void TileSetEditor::_select_next_shape() { + if (get_current_tile() == -1) { + _select_next_subtile(); + } else if (edit_mode != EDITMODE_COLLISION) { + _select_next_subtile(); + } else { + Vector2i edited_coord = Vector2(); + if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { + edited_coord = edited_shape_coord; + } + SubtileData data = current_tile_data[edited_coord]; + if (data.collisions.size() == 0) { + _select_next_subtile(); + } else { + int index = data.collisions.find(edited_collision_shape); + if (index < 0) { + edited_collision_shape = data.collisions[0]; + } else if (index == data.collisions.size() - 1) { + _select_next_subtile(); + } else { + edited_collision_shape = data.collisions[index + 1]; + } + } + current_shape.resize(0); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; + + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Vector2 shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + current_tile_region.position += shape_anchor; + + if (edited_collision_shape.is_valid()) { + for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { + current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + } + } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } +} + +void TileSetEditor::_select_previous_shape() { + if (get_current_tile() == -1) { + _select_previous_subtile(); + if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) { + SubtileData data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + edited_collision_shape = data.collisions[data.collisions.size() - 1]; + } + } else { + return; + } + } else if (edit_mode != EDITMODE_COLLISION) { + _select_previous_subtile(); + } else { + Vector2i edited_coord = Vector2(); + if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { + edited_coord = edited_shape_coord; + } + SubtileData data = current_tile_data[edited_coord]; + if (data.collisions.size() == 0) { + _select_previous_subtile(); + data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + edited_collision_shape = data.collisions[data.collisions.size() - 1]; + } + } else { + int index = data.collisions.find(edited_collision_shape); + if (index < 0) { + edited_collision_shape = data.collisions[data.collisions.size() - 1]; + } else if (index == 0) { + _select_previous_subtile(); + data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + edited_collision_shape = data.collisions[data.collisions.size() - 1]; + } + } else { + edited_collision_shape = data.collisions[index - 1]; + } + } + current_shape.resize(0); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; + + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Vector2 shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + current_tile_region.position += shape_anchor; + + if (edited_collision_shape.is_valid()) { + for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { + current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + } + } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } +} + void TileSetEditor::_set_snap_step(Vector2 p_val) { snap_step.x = CLAMP(p_val.x, 0, 256); snap_step.y = CLAMP(p_val.y, 0, 256); @@ -2421,6 +2565,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } void TileSetEditor::select_coord(const Vector2 &coord) { + _update_tile_data(); current_shape = PoolVector2Array(); if (get_current_tile() == -1) return; @@ -2642,7 +2787,7 @@ void TileSetEditor::update_workspace_tile_mode() { for (int i = 0; i < EDITMODE_MAX; i++) { tool_editmode[i]->hide(); } - for (int i = 0; i < ZOOM_OUT; i++) { + for (int i = TOOL_SELECT; i < ZOOM_OUT; i++) { tools[i]->hide(); } diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index c9a1123618..d3efbff35e 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -94,6 +94,12 @@ class TileSetEditor : public HSplitContainer { TOOL_MAX }; + struct SubtileData { + Array collisions; + Ref occlusion_shape; + Ref navigation_shape; + }; + Ref tileset; TilesetEditorContext *helper; EditorNode *editor; @@ -117,6 +123,7 @@ class TileSetEditor : public HSplitContainer { bool draw_edited_region; Vector2 edited_shape_coord; PoolVector2Array current_shape; + Map current_tile_data; Map bitmask_map_copy; Vector2 snap_step; @@ -190,12 +197,15 @@ private: void _on_priority_changed(float val); void _on_z_index_changed(float val); void _on_grid_snap_toggled(bool p_val); + void _update_tile_data(); void _select_next_tile(); void _select_previous_tile(); Array _get_tiles_in_current_texture(bool sorted = false); bool _sort_tiles(Variant p_a, Variant p_b); void _select_next_subtile(); void _select_previous_subtile(); + void _select_next_shape(); + void _select_previous_shape(); void _set_snap_step(Vector2 p_val); void _set_snap_off(Vector2 p_val); void _set_snap_sep(Vector2 p_val); -- cgit v1.2.3 From 7b933d70a8eccdfa06754660b77178b5a62910e6 Mon Sep 17 00:00:00 2001 From: Mariano Suligoy Date: Sat, 2 Mar 2019 18:50:19 -0300 Subject: TileSetEditor: Allow to toggle Convex/Concave collisions. Alternative fix to #24003 --- editor/plugins/tile_set_editor_plugin.cpp | 194 +++++++++++++++++++++++++----- editor/plugins/tile_set_editor_plugin.h | 10 +- 2 files changed, 170 insertions(+), 34 deletions(-) (limited to 'editor/plugins') diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 26ee6a9f83..5b7fe4db12 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -243,6 +243,7 @@ void TileSetEditor::_notification(int p_what) { tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons")); + _update_toggle_shape_button(); tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons")); tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons")); @@ -411,6 +412,12 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tools[SHAPE_NEW_POLYGON]->set_button_group(tg); tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon.")); + separator_shape_toggle = memnew(VSeparator); + toolbar->add_child(separator_shape_toggle); + tools[SHAPE_TOGGLE_TYPE] = memnew(ToolButton); + tools[SHAPE_TOGGLE_TYPE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_TOGGLE_TYPE)); + toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]); + separator_delete = memnew(VSeparator); toolbar->add_child(separator_delete); tools[SHAPE_DELETE] = memnew(ToolButton); @@ -765,6 +772,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { } break; default: {} } + _update_toggle_shape_button(); workspace->update(); } @@ -1367,8 +1375,7 @@ void TileSetEditor::_on_workspace_input(const Ref &p_ie) { } undo_redo->create_action(TTR("Edit Collision Polygon")); - undo_redo->add_do_method(edited_collision_shape.ptr(), "set_points", points); - undo_redo->add_undo_method(edited_collision_shape.ptr(), "set_points", edited_collision_shape->get_points()); + _set_edited_shape_points(points); undo_redo->add_do_method(this, "_select_edited_shape_coord"); undo_redo->add_undo_method(this, "_select_edited_shape_coord"); undo_redo->commit_action(); @@ -1446,7 +1453,7 @@ void TileSetEditor::_on_workspace_input(const Ref &p_ie) { workspace->update(); } else { creating_shape = true; - edited_collision_shape = Ref(); + _set_edited_collision_shape(Ref()); current_shape.resize(0); current_shape.push_back(snap_point(pos)); workspace->update(); @@ -1466,7 +1473,7 @@ void TileSetEditor::_on_workspace_input(const Ref &p_ie) { } else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - edited_collision_shape = Ref(); + _set_edited_collision_shape(Ref()); current_shape.resize(0); current_shape.push_back(snap_point(shape_anchor)); current_shape.push_back(snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); @@ -1511,6 +1518,45 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->add_do_method(workspace, "update"); undo_redo->add_undo_method(workspace, "update"); undo_redo->commit_action(); + } else if (p_tool == SHAPE_TOGGLE_TYPE) { + if (edited_collision_shape.is_valid()) { + Ref convex = edited_collision_shape; + Ref concave = edited_collision_shape; + Ref previous_shape = edited_collision_shape; + Array sd = tileset->call("tile_get_shapes", get_current_tile()); + + if (convex.is_valid()) { + // Make concave + undo_redo->create_action(TTR("Make Polygon Concave")); + Ref _concave = memnew(ConcavePolygonShape2D); + edited_collision_shape = _concave; + _set_edited_shape_points(_get_collision_shape_points(convex)); + } else if (concave.is_valid()) { + // Make convex + undo_redo->create_action(TTR("Make Polygon Convex")); + Ref _convex = memnew(ConvexPolygonShape2D); + edited_collision_shape = _convex; + _set_edited_shape_points(_get_collision_shape_points(concave)); + } else { + // Shoudn't haphen + } + for (int i = 0; i < sd.size(); i++) { + if (sd[i].get("shape") == previous_shape) { + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate()); + sd.remove(i); + sd.insert(i, edited_collision_shape); + undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); + break; + } + } + _update_toggle_shape_button(); + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } } else if (p_tool == SELECT_NEXT) { _select_next_shape(); } else if (p_tool == SELECT_PREVIOUS) { @@ -1629,6 +1675,48 @@ void TileSetEditor::_on_grid_snap_toggled(bool p_val) { workspace->update(); } +Vector TileSetEditor::_get_collision_shape_points(const Ref &p_shape) { + Ref convex = p_shape; + Ref concave = p_shape; + if (convex.is_valid()) { + return convex->get_points(); + } else if (concave.is_valid()) { + Vector points; + for (int i = 0; i < concave->get_segments().size(); i += 2) { + points.push_back(concave->get_segments()[i]); + } + return points; + } else { + return Vector(); + } +} + +Vector TileSetEditor::_get_edited_shape_points() { + return _get_collision_shape_points(edited_collision_shape); +} + +void TileSetEditor::_set_edited_shape_points(const Vector points) { + Ref convex = edited_collision_shape; + Ref concave = edited_collision_shape; + if (convex.is_valid()) { + undo_redo->add_do_method(convex.ptr(), "set_points", points); + undo_redo->add_undo_method(convex.ptr(), "set_points", _get_edited_shape_points()); + } else if (concave.is_valid()) { + PoolVector2Array segments; + for (int i = 0; i < points.size() - 1; i++) { + segments.push_back(points[i]); + segments.push_back(points[i + 1]); + } + segments.push_back(points[points.size() - 1]); + segments.push_back(points[0]); + concave->set_segments(segments); + undo_redo->add_do_method(concave.ptr(), "set_segments", segments); + undo_redo->add_undo_method(concave.ptr(), "set_segments", concave->get_segments()); + } else { + // Invalid shape + } +} + void TileSetEditor::_update_tile_data() { current_tile_data.clear(); if (get_current_tile() < 0) @@ -1664,6 +1752,27 @@ void TileSetEditor::_update_tile_data() { } } +void TileSetEditor::_update_toggle_shape_button() { + Ref convex = edited_collision_shape; + Ref concave = edited_collision_shape; + separator_shape_toggle->show(); + tools[SHAPE_TOGGLE_TYPE]->show(); + if (edit_mode != EDITMODE_COLLISION || !edited_collision_shape.is_valid()) { + separator_shape_toggle->hide(); + tools[SHAPE_TOGGLE_TYPE]->hide(); + } else if (concave.is_valid()) { + tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConvexPolygonShape2D", "EditorIcons")); + tools[SHAPE_TOGGLE_TYPE]->set_text("Make Convex"); + } else if (convex.is_valid()) { + tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); + tools[SHAPE_TOGGLE_TYPE]->set_text("Make Concave"); + } else { + // Shoudn't happen + separator_shape_toggle->hide(); + tools[SHAPE_TOGGLE_TYPE]->hide(); + } +} + void TileSetEditor::_select_next_tile() { Array tiles = _get_tiles_in_current_texture(true); if (tiles.size() == 0) { @@ -1842,11 +1951,11 @@ void TileSetEditor::_select_next_shape() { } else { int index = data.collisions.find(edited_collision_shape); if (index < 0) { - edited_collision_shape = data.collisions[0]; + _set_edited_collision_shape(data.collisions[0]); } else if (index == data.collisions.size() - 1) { _select_next_subtile(); } else { - edited_collision_shape = data.collisions[index + 1]; + _set_edited_collision_shape(data.collisions[index + 1]); } } current_shape.resize(0); @@ -1861,8 +1970,8 @@ void TileSetEditor::_select_next_shape() { current_tile_region.position += shape_anchor; if (edited_collision_shape.is_valid()) { - for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); } } workspace->update(); @@ -1877,7 +1986,7 @@ void TileSetEditor::_select_previous_shape() { if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) { SubtileData data = current_tile_data[Vector2i(edited_shape_coord)]; if (data.collisions.size() > 1) { - edited_collision_shape = data.collisions[data.collisions.size() - 1]; + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); } } else { return; @@ -1894,22 +2003,23 @@ void TileSetEditor::_select_previous_shape() { _select_previous_subtile(); data = current_tile_data[Vector2i(edited_shape_coord)]; if (data.collisions.size() > 1) { - edited_collision_shape = data.collisions[data.collisions.size() - 1]; + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); } } else { int index = data.collisions.find(edited_collision_shape); if (index < 0) { - edited_collision_shape = data.collisions[data.collisions.size() - 1]; + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); } else if (index == 0) { _select_previous_subtile(); data = current_tile_data[Vector2i(edited_shape_coord)]; if (data.collisions.size() > 1) { - edited_collision_shape = data.collisions[data.collisions.size() - 1]; + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); } } else { - edited_collision_shape = data.collisions[index - 1]; + _set_edited_collision_shape(data.collisions[index - 1]); } } + current_shape.resize(0); Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); current_tile_region.position += WORKSPACE_MARGIN; @@ -1922,8 +2032,8 @@ void TileSetEditor::_select_previous_shape() { current_tile_region.position += shape_anchor; if (edited_collision_shape.is_valid()) { - for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); } } workspace->update(); @@ -1932,6 +2042,11 @@ void TileSetEditor::_select_previous_shape() { } } +void TileSetEditor::_set_edited_collision_shape(const Ref &p_shape) { + edited_collision_shape = p_shape; + _update_toggle_shape_button(); +} + void TileSetEditor::_set_snap_step(Vector2 p_val) { snap_step.x = CLAMP(p_val.x, 0, 256); snap_step.y = CLAMP(p_val.y, 0, 256); @@ -2228,16 +2343,29 @@ void TileSetEditor::draw_polygon_shapes() { } anchor += WORKSPACE_MARGIN; anchor += tileset->tile_get_region(t_id).position; - Ref shape = sd[i].shape; + Ref shape = sd[i].shape; if (shape.is_valid()) { Color c_bg; Color c_border; + Ref convex = shape; + bool is_convex = convex.is_valid(); if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); + if (is_convex) { + c_bg = Color(0, 1, 1, 0.5); + c_border = Color(0, 1, 1); + } else { + c_bg = Color(0.8, 0, 1, 0.5); + c_border = Color(0.8, 0, 1); + } } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); + if (is_convex) { + c_bg = Color(0.9, 0.7, 0.07, 0.5); + c_border = Color(0.9, 0.7, 0.07, 1); + + } else { + c_bg = Color(0.9, 0.45, 0.075, 0.5); + c_border = Color(0.9, 0.45, 0.075); + } } Vector polygon; Vector colors; @@ -2247,8 +2375,8 @@ void TileSetEditor::draw_polygon_shapes() { colors.push_back(c_bg); } } else { - for (int j = 0; j < shape->get_points().size(); j++) { - polygon.push_back(shape->get_points()[j] + anchor); + for (int j = 0; j < _get_collision_shape_points(shape).size(); j++) { + polygon.push_back(_get_collision_shape_points(shape)[j] + anchor); colors.push_back(c_bg); } } @@ -2465,11 +2593,11 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { if (current_shape.size() >= 3) { Ref shape = memnew(ConvexPolygonShape2D); - Vector segments; + Vector points; float p_total = 0; for (int i = 0; i < current_shape.size(); i++) { - segments.push_back(current_shape[i] - shape_anchor); + points.push_back(current_shape[i] - shape_anchor); if (i != current_shape.size() - 1) p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y))); @@ -2478,9 +2606,9 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } if (p_total < 0) - segments.invert(); + points.invert(); - shape->set_points(segments); + shape->set_points(points); undo_redo->create_action(TTR("Create Collision Polygon")); // Necessary to get the version that returns a Array instead of a Vector. @@ -2573,7 +2701,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_tile_region.position += WORKSPACE_MARGIN; if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) - edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0); + _set_edited_collision_shape(tileset->tile_get_shape(get_current_tile(), 0)); if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile())) edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) @@ -2582,8 +2710,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { - for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_OCCLUSION) { @@ -2610,13 +2738,13 @@ void TileSetEditor::select_coord(const Vector2 &coord) { for (int i = 0; i < sd.size(); i++) { if (sd[i].autotile_coord == coord) { if (edited_collision_shape != sd[i].shape) - edited_collision_shape = sd[i].shape; + _set_edited_collision_shape(sd[i].shape); found_collision_shape = true; break; } } if (!found_collision_shape) - edited_collision_shape = Ref(NULL); + _set_edited_collision_shape(Ref(NULL)); if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord)) edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), coord); if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord)) @@ -2631,8 +2759,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { - for (int j = 0; j < edited_collision_shape->get_points().size(); j++) { - current_shape.push_back(edited_collision_shape->get_points()[j] + shape_anchor); + for (int j = 0; j < _get_edited_shape_points().size(); j++) { + current_shape.push_back(_get_edited_shape_points()[j] + shape_anchor); } } } else if (edit_mode == EDITMODE_OCCLUSION) { diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index d3efbff35e..01460189fb 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -34,6 +34,7 @@ #include "editor/editor_name_dialog.h" #include "editor/editor_node.h" #include "scene/2d/sprite.h" +#include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" @@ -84,6 +85,7 @@ class TileSetEditor : public HSplitContainer { BITMASK_CLEAR, SHAPE_NEW_POLYGON, SHAPE_NEW_RECTANGLE, + SHAPE_TOGGLE_TYPE, SHAPE_DELETE, SHAPE_KEEP_INSIDE_TILE, TOOL_GRID_SNAP, @@ -130,7 +132,7 @@ class TileSetEditor : public HSplitContainer { Vector2 snap_offset; Vector2 snap_separation; - Ref edited_collision_shape; + Ref edited_collision_shape; Ref edited_occlusion_shape; Ref edited_navigation_shape; @@ -146,6 +148,7 @@ class TileSetEditor : public HSplitContainer { HSeparator *separator_editmode; HBoxContainer *toolbar; ToolButton *tools[TOOL_MAX]; + VSeparator *separator_shape_toggle; VSeparator *separator_bitmask; VSeparator *separator_delete; VSeparator *separator_grid; @@ -197,7 +200,11 @@ private: void _on_priority_changed(float val); void _on_z_index_changed(float val); void _on_grid_snap_toggled(bool p_val); + Vector _get_collision_shape_points(const Ref &p_shape); + Vector _get_edited_shape_points(); + void _set_edited_shape_points(const Vector points); void _update_tile_data(); + void _update_toggle_shape_button(); void _select_next_tile(); void _select_previous_tile(); Array _get_tiles_in_current_texture(bool sorted = false); @@ -206,6 +213,7 @@ private: void _select_previous_subtile(); void _select_next_shape(); void _select_previous_shape(); + void _set_edited_collision_shape(const Ref &p_shape); void _set_snap_step(Vector2 p_val); void _set_snap_off(Vector2 p_val); void _set_snap_sep(Vector2 p_val); -- cgit v1.2.3