diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml
index 9468763b6e3..f9505124ef4 100644
--- a/doc/classes/TileData.xml
+++ b/doc/classes/TileData.xml
@@ -16,6 +16,13 @@
Adds a collision polygon to the tile on the given TileSet physics layer.
+
+
+
+
+ Adds an occlusion polygon to the tile on the TileSet occlusion layer with index [param layer_id].
+
+
@@ -78,7 +85,7 @@
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
-
+
@@ -89,6 +96,25 @@
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
+
+
+
+
+
+
+
+
+ Returns the occluder polygon at index [param polygon_index] from the TileSet occlusion layer with index [param layer_id].
+ The [param flip_h], [param flip_v], and [param transpose] parameters can be [code]true[/code] to transform the returned polygon.
+
+
+
+
+
+
+ Returns the number of occluder polygons of the tile in the TileSet occlusion layer with index [param layer_id].
+
+
@@ -119,6 +145,14 @@
Removes the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
+
+
+
+
+
+ Removes the polygon at index [param polygon_index] for TileSet occlusion layer with index [param layer_id].
+
+
@@ -194,7 +228,7 @@
Sets the navigation polygon for the TileSet navigation layer with index [param layer_id].
-
+
@@ -202,6 +236,23 @@
Sets the occluder for the TileSet occlusion layer with index [param layer_id].
+
+
+
+
+
+
+ Sets the occluder for polygon with index [param polygon_index] in the TileSet occlusion layer with index [param layer_id].
+
+
+
+
+
+
+
+ Sets the occluder polygon count in the TileSet occlusion layer with index [param layer_id].
+
+
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 8dbf58e2285..79915012a88 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -1482,30 +1482,36 @@ void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Tra
debug_occlusion_color.push_back(color);
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
- Ref occluder = tile_data->get_occluder(occlusion_layer);
- if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
- p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
+ for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
+ Ref occluder = tile_data->get_occluder_polygon(occlusion_layer, i);
+ if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
+ p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
+ }
}
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
}
Variant TileDataOcclusionShapeEditor::_get_painted_value() {
- Ref occluder_polygon;
- if (polygon_editor->get_polygon_count() >= 1) {
+ Array polygons;
+ for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
+ Ref occluder_polygon;
occluder_polygon.instantiate();
- occluder_polygon->set_polygon(polygon_editor->get_polygon(0));
+ occluder_polygon->set_polygon(polygon_editor->get_polygon(i));
+ polygons.push_back(occluder_polygon);
}
- return occluder_polygon;
+ return polygons;
}
void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL(tile_data);
- Ref occluder_polygon = tile_data->get_occluder(occlusion_layer);
polygon_editor->clear_polygons();
- if (occluder_polygon.is_valid()) {
- polygon_editor->add_polygon(occluder_polygon->get_polygon());
+ for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
+ Ref occluder_polygon = tile_data->get_occluder_polygon(occlusion_layer, i);
+ if (occluder_polygon.is_valid()) {
+ polygon_editor->add_polygon(occluder_polygon->get_polygon());
+ }
}
polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile);
}
@@ -1513,8 +1519,13 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile
void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL(tile_data);
- Ref occluder_polygon = p_value;
- tile_data->set_occluder(occlusion_layer, occluder_polygon);
+
+ Array polygons = p_value;
+ tile_data->set_occluder_polygons_count(occlusion_layer, polygons.size());
+ for (int i = 0; i < polygons.size(); i++) {
+ Ref occluder_polygon = polygons[i];
+ tile_data->set_occluder_polygon(occlusion_layer, i, occluder_polygon);
+ }
polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile);
}
@@ -1522,7 +1533,11 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl
Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL_V(tile_data, Variant());
- return tile_data->get_occluder(occlusion_layer);
+ Array polygons;
+ for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
+ polygons.push_back(tile_data->get_occluder_polygon(occlusion_layer, i));
+ }
+ return polygons;
}
void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap &p_previous_values, const Variant &p_new_value) {
@@ -1548,6 +1563,7 @@ void TileDataOcclusionShapeEditor::_notification(int p_what) {
TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() {
polygon_editor = memnew(GenericTilePolygonEditor);
+ polygon_editor->set_multiple_polygon_mode(true);
add_child(polygon_editor);
}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 224c4e434f3..b1417b2878f 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2768,15 +2768,7 @@ void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
void EditorPropertyTilePolygon::_polygons_changed() {
if (String(count_property).is_empty()) {
- if (base_type == "OccluderPolygon2D") {
- // Single OccluderPolygon2D.
- Ref occluder;
- if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
- occluder.instantiate();
- occluder->set_polygon(generic_tile_polygon_editor->get_polygon(0));
- }
- emit_changed(get_edited_property(), occluder);
- } else if (base_type == "NavigationPolygon") {
+ if (base_type == "NavigationPolygon") {
Ref navigation_polygon;
if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
navigation_polygon.instantiate();
@@ -2798,19 +2790,24 @@ void EditorPropertyTilePolygon::_polygons_changed() {
emit_changed(get_edited_property(), navigation_polygon);
}
} else {
- if (base_type.is_empty()) {
- // Multiple array of vertices.
- Vector changed_properties;
- Array values;
- int count = generic_tile_polygon_editor->get_polygon_count();
- changed_properties.push_back(count_property);
- values.push_back(count);
- for (int i = 0; i < count; i++) {
- changed_properties.push_back(vformat(element_pattern, i));
+ // Multiple array of vertices or OccluderPolygon2D.
+ Vector changed_properties;
+ Array values;
+ int count = generic_tile_polygon_editor->get_polygon_count();
+ changed_properties.push_back(count_property);
+ values.push_back(count);
+ for (int i = 0; i < count; i++) {
+ changed_properties.push_back(vformat(element_pattern, i));
+ if (base_type.is_empty()) {
values.push_back(generic_tile_polygon_editor->get_polygon(i));
+ } else if (base_type == "OccluderPolygon2D") {
+ Ref occluder;
+ occluder.instantiate();
+ occluder->set_polygon(generic_tile_polygon_editor->get_polygon(i));
+ values.push_back(occluder);
}
- emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
}
+ emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
}
}
@@ -2834,15 +2831,8 @@ void EditorPropertyTilePolygon::update_property() {
generic_tile_polygon_editor->clear_polygons();
if (String(count_property).is_empty()) {
- if (base_type == "OccluderPolygon2D") {
- // Single OccluderPolygon2D.
- Ref occluder = get_edited_property_value();
- generic_tile_polygon_editor->clear_polygons();
- if (occluder.is_valid()) {
- generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
- }
- } else if (base_type == "NavigationPolygon") {
- // Single OccluderPolygon2D.
+ if (base_type == "NavigationPolygon") {
+ // Single NavigationPolygon.
Ref navigation_polygon = get_edited_property_value();
generic_tile_polygon_editor->clear_polygons();
if (navigation_polygon.is_valid()) {
@@ -2859,6 +2849,15 @@ void EditorPropertyTilePolygon::update_property() {
for (int i = 0; i < count; i++) {
generic_tile_polygon_editor->add_polygon(get_edited_object()->get(vformat(element_pattern, i)));
}
+ } else if (base_type == "OccluderPolygon2D") {
+ // Multiple OccluderPolygon2D.
+ generic_tile_polygon_editor->clear_polygons();
+ for (int i = 0; i < count; i++) {
+ Ref occluder = get_edited_object()->get(vformat(element_pattern, i));
+ if (occluder.is_valid()) {
+ generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
+ }
+ }
}
}
}
@@ -2899,16 +2898,30 @@ bool EditorInspectorPluginTileData::can_handle(Object *p_object) {
bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide) {
Vector components = String(p_path).split("/", true, 2);
- if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
+ if (components.size() >= 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
ERR_FAIL_COND_V(layer_index < 0, false);
- if (components[1] == "polygon") {
+ if (components[1] == "polygons_count") {
EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
- ep->setup_single_mode(p_path, "OccluderPolygon2D");
- add_property_editor(p_path, ep);
+ ep->setup_multiple_mode(vformat("occlusion_layer_%d/polygons", layer_index), vformat("occlusion_layer_%d/polygons_count", layer_index), vformat("occlusion_layer_%d/polygon_%%d/polygon", layer_index), "OccluderPolygon2D");
+ Vector properties;
+ properties.push_back(p_path);
+ int count = p_object->get(vformat("occlusion_layer_%d/polygons_count", layer_index));
+ for (int i = 0; i < count; i++) {
+ properties.push_back(vformat("occlusion_layer_%d/polygon_%d/polygon", layer_index, i));
+ }
+ add_property_editor_for_multiple_properties("Polygons", properties, ep);
return true;
}
+ // We keep the original editor for now, but here is the code that could be used if we need a custom editor for each polygon:
+ /*else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
+ int polygon_index = components[1].trim_prefix("polygon_").to_int();
+ ERR_FAIL_COND_V(polygon_index < 0, false);
+ if (components[2] == "polygon") {
+ return true;
+ }
+ }*/
} else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
// Physics layers.
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index ba0958e74b7..ebb03e4e739 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -443,13 +443,15 @@ void TileMapLayer::_rendering_notification(int p_what) {
Transform2D tilemap_xform = get_global_transform();
for (KeyValue &kv : tile_map_layer_data) {
const CellData &cell_data = kv.value;
- for (const RID &occluder : cell_data.occluders) {
- if (occluder.is_null()) {
- continue;
+ for (const LocalVector &polygons : cell_data.occluders) {
+ for (const RID &rid : polygons) {
+ if (rid.is_null()) {
+ continue;
+ }
+ Transform2D xform(0, tile_set->map_to_local(kv.key));
+ rs->canvas_light_occluder_attach_to_canvas(rid, get_canvas());
+ rs->canvas_light_occluder_set_transform(rid, tilemap_xform * xform);
}
- Transform2D xform(0, tile_set->map_to_local(kv.key));
- rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
- rs->canvas_light_occluder_set_transform(occluder, tilemap_xform * xform);
}
}
}
@@ -557,8 +559,10 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) {
RenderingServer *rs = RenderingServer::get_singleton();
// Free the occluders.
- for (const RID &rid : r_cell_data.occluders) {
- rs->free(rid);
+ for (const LocalVector &polygons : r_cell_data.occluders) {
+ for (const RID &rid : polygons) {
+ rs->free(rid);
+ }
}
r_cell_data.occluders.clear();
}
@@ -566,11 +570,12 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) {
void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
RenderingServer *rs = RenderingServer::get_singleton();
- // Free unused occluders then resize the occluders array.
+ // Free unused occluders then resize the occluder array.
for (uint32_t i = tile_set->get_occlusion_layers_count(); i < r_cell_data.occluders.size(); i++) {
- RID occluder_id = r_cell_data.occluders[i];
- if (occluder_id.is_valid()) {
- rs->free(occluder_id);
+ for (const RID &occluder_id : r_cell_data.occluders[i]) {
+ if (occluder_id.is_valid()) {
+ rs->free(occluder_id);
+ }
}
}
r_cell_data.occluders.resize(tile_set->get_occlusion_layers_count());
@@ -598,30 +603,42 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
// Create, update or clear occluders.
bool needs_set_not_interpolated = is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && !is_physics_interpolated();
for (uint32_t occlusion_layer_index = 0; occlusion_layer_index < r_cell_data.occluders.size(); occlusion_layer_index++) {
- Ref occluder_polygon = tile_data->get_occluder(occlusion_layer_index);
+ LocalVector &occluders = r_cell_data.occluders[occlusion_layer_index];
- RID &occluder = r_cell_data.occluders[occlusion_layer_index];
-
- if (occluder_polygon.is_valid()) {
- // Create or update occluder.
- Transform2D xform;
- xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
- if (!occluder.is_valid()) {
- occluder = rs->canvas_light_occluder_create();
- if (needs_set_not_interpolated) {
- rs->canvas_light_occluder_set_interpolated(occluder, false);
- }
+ // Free unused occluders then resize the occluders array.
+ for (uint32_t i = tile_data->get_occluder_polygons_count(occlusion_layer_index); i < r_cell_data.occluders[occlusion_layer_index].size(); i++) {
+ RID occluder_id = occluders[i];
+ if (occluder_id.is_valid()) {
+ rs->free(occluder_id);
}
- rs->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform);
- rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid());
- rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
- rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index));
- rs->canvas_light_occluder_set_as_sdf_collision(occluder, tile_set->get_occlusion_layer_sdf_collision(occlusion_layer_index));
- } else {
- // Clear occluder.
- if (occluder.is_valid()) {
- rs->free(occluder);
- occluder = RID();
+ }
+ occluders.resize(tile_data->get_occluder_polygons_count(occlusion_layer_index));
+
+ for (uint32_t occlusion_polygon_index = 0; occlusion_polygon_index < occluders.size(); occlusion_polygon_index++) {
+ RID &occluder = occluders[occlusion_polygon_index];
+ Ref occluder_polygon = tile_data->get_occluder_polygon(occlusion_layer_index, occlusion_polygon_index);
+ if (occluder_polygon.is_valid()) {
+ // Create or update occluder.
+
+ Transform2D xform;
+ xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
+ if (!occluder.is_valid()) {
+ occluder = rs->canvas_light_occluder_create();
+ if (needs_set_not_interpolated) {
+ rs->canvas_light_occluder_set_interpolated(occluder, false);
+ }
+ }
+ rs->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform);
+ rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder_polygon(occlusion_layer_index, occlusion_polygon_index, flip_h, flip_v, transpose)->get_rid());
+ rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
+ rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index));
+ rs->canvas_light_occluder_set_as_sdf_collision(occluder, tile_set->get_occlusion_layer_sdf_collision(occlusion_layer_index));
+ } else {
+ // Clear occluder.
+ if (occluder.is_valid()) {
+ rs->free(occluder);
+ occluder = RID();
+ }
}
}
}
@@ -1709,11 +1726,13 @@ void TileMapLayer::_physics_interpolated_changed() {
}
for (const KeyValue &E : tile_map_layer_data) {
- for (const RID &occluder : E.value.occluders) {
- if (occluder.is_valid()) {
- rs->canvas_light_occluder_set_interpolated(occluder, interpolated);
- if (needs_reset) {
- rs->canvas_light_occluder_reset_physics_interpolation(occluder);
+ for (const LocalVector &polygons : E.value.occluders) {
+ for (const RID &occluder_id : polygons) {
+ if (occluder_id.is_valid()) {
+ rs->canvas_light_occluder_set_interpolated(occluder_id, interpolated);
+ if (needs_reset) {
+ rs->canvas_light_occluder_reset_physics_interpolation(occluder_id);
+ }
}
}
}
diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h
index 2a986667bd2..cc0a5b49fb9 100644
--- a/scene/2d/tile_map_layer.h
+++ b/scene/2d/tile_map_layer.h
@@ -108,7 +108,7 @@ struct CellData {
// Rendering.
Ref rendering_quadrant;
SelfList rendering_quadrant_list_element;
- LocalVector occluders;
+ LocalVector> occluders;
// Physics.
LocalVector bodies;
diff --git a/scene/resources/2d/tile_set.compat.inc b/scene/resources/2d/tile_set.compat.inc
index 873ae3aa93f..58e33f7b357 100644
--- a/scene/resources/2d/tile_set.compat.inc
+++ b/scene/resources/2d/tile_set.compat.inc
@@ -37,7 +37,7 @@ Ref TileData::_get_navigation_polygon_bind_compat_84660(int p
}
Ref TileData::_get_occluder_bind_compat_84660(int p_layer_id) const {
- return get_occluder(p_layer_id, false, false, false);
+ return get_occluder_polygon(p_layer_id, 0, false, false, false);
}
void TileData::_bind_compatibility_methods() {
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index dd6ae5096a6..49d84bfb1b9 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -3444,7 +3444,8 @@ void TileSet::_compatibility_conversion() {
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
}
occluder->set_polygon(polygon);
- tile_data->set_occluder(0, occluder);
+ tile_data->add_occluder_polygon(0);
+ tile_data->set_occluder_polygon(0, 0, occluder);
}
if (ctd->navigation.is_valid()) {
if (get_navigation_layers_count() < 1) {
@@ -3558,7 +3559,8 @@ void TileSet::_compatibility_conversion() {
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
}
occluder->set_polygon(polygon);
- tile_data->set_occluder(0, occluder);
+ tile_data->add_occluder_polygon(0);
+ tile_data->set_occluder_polygon(0, 0, occluder);
}
if (ctd->autotile_navpoly_map.has(coords)) {
if (get_navigation_layers_count() < 1) {
@@ -6220,33 +6222,86 @@ int TileData::get_y_sort_origin() const {
return y_sort_origin;
}
+#ifndef DISABLE_DEPRECATED
void TileData::set_occluder(int p_layer_id, Ref p_occluder_polygon) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
- occluders.write[p_layer_id].occluder = p_occluder_polygon;
- occluders.write[p_layer_id].transformed_occluders.clear();
+ if (get_occluder_polygons_count(p_layer_id) == 0) {
+ add_occluder_polygon(p_layer_id);
+ }
+ set_occluder_polygon(p_layer_id, 0, p_occluder_polygon);
emit_signal(CoreStringName(changed));
}
Ref TileData::get_occluder(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref());
+ if (get_occluder_polygons_count(p_layer_id) == 0) {
+ return Ref();
+ }
+ return get_occluder_polygon(p_layer_id, 0, p_flip_h, p_flip_v, p_transpose);
+}
+#endif // DISABLE_DEPRECATED
+
+void TileData::set_occluder_polygons_count(int p_layer_id, int p_polygons_count) {
+ ERR_FAIL_INDEX(p_layer_id, occluders.size());
+ ERR_FAIL_COND(p_polygons_count < 0);
+ if (p_polygons_count == occluders.write[p_layer_id].polygons.size()) {
+ return;
+ }
+ occluders.write[p_layer_id].polygons.resize(p_polygons_count);
+ notify_property_list_changed();
+ emit_signal(CoreStringName(changed));
+}
+
+int TileData::get_occluder_polygons_count(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), 0);
+ return occluders[p_layer_id].polygons.size();
+}
+
+void TileData::add_occluder_polygon(int p_layer_id) {
+ ERR_FAIL_INDEX(p_layer_id, occluders.size());
+ occluders.write[p_layer_id].polygons.push_back(OcclusionLayerTileData::PolygonOccluderTileData());
+ emit_signal(CoreStringName(changed));
+}
+
+void TileData::remove_occluder_polygon(int p_layer_id, int p_polygon_index) {
+ ERR_FAIL_INDEX(p_layer_id, occluders.size());
+ ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
+ occluders.write[p_layer_id].polygons.remove_at(p_polygon_index);
+ emit_signal(CoreStringName(changed));
+}
+
+void TileData::set_occluder_polygon(int p_layer_id, int p_polygon_index, const Ref &p_occluder_polygon) {
+ ERR_FAIL_INDEX(p_layer_id, occluders.size());
+ ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
+
+ OcclusionLayerTileData::PolygonOccluderTileData &polygon_occluder_tile_data = occluders.write[p_layer_id].polygons.write[p_polygon_index];
+ polygon_occluder_tile_data.occluder_polygon = p_occluder_polygon;
+ polygon_occluder_tile_data.transformed_polygon_occluders.clear();
+ emit_signal(CoreStringName(changed));
+}
+
+Ref TileData::get_occluder_polygon(int p_layer_id, int p_polygon_index, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
+ ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref());
+ ERR_FAIL_INDEX_V(p_polygon_index, occluders[p_layer_id].polygons.size(), Ref());
const OcclusionLayerTileData &layer_tile_data = occluders[p_layer_id];
+ const Ref &occluder_polygon = layer_tile_data.polygons[p_polygon_index].occluder_polygon;
int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2;
if (key == 0) {
- return layer_tile_data.occluder;
+ return occluder_polygon;
}
- if (layer_tile_data.occluder.is_null()) {
+ if (occluder_polygon.is_null()) {
return Ref();
}
- HashMap>::Iterator I = layer_tile_data.transformed_occluders.find(key);
+ HashMap>::Iterator I = layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders.find(key);
if (!I) {
Ref transformed_polygon;
transformed_polygon.instantiate();
- transformed_polygon->set_polygon(get_transformed_vertices(layer_tile_data.occluder->get_polygon(), p_flip_h, p_flip_v, p_transpose));
- layer_tile_data.transformed_occluders[key] = transformed_polygon;
+ transformed_polygon->set_polygon(get_transformed_vertices(occluder_polygon->get_polygon(), p_flip_h, p_flip_v, p_transpose));
+ layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders[key] = transformed_polygon;
return transformed_polygon;
} else {
return I->value;
@@ -6594,13 +6649,37 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
#endif
Vector components = String(p_name).split("/", true, 2);
-
- if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
+ if (components.size() >= 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
ERR_FAIL_COND_V(layer_index < 0, false);
- if (components[1] == "polygon") {
- Ref polygon = p_value;
+ if (components.size() == 2) {
+ if (components[1] == "polygon") {
+ // Kept for compatibility.
+ Ref polygon = p_value;
+ if (layer_index >= occluders.size()) {
+ if (tile_set) {
+ return false;
+ } else {
+ occluders.resize(layer_index + 1);
+ }
+ }
+ if (get_occluder_polygons_count(layer_index) == 0) {
+ add_occluder_polygon(layer_index);
+ }
+ set_occluder_polygon(layer_index, 0, polygon);
+ return true;
+ } else if (components[1] == "polygons_count") {
+ if (p_value.get_type() != Variant::INT) {
+ return false;
+ }
+ set_occluder_polygons_count(layer_index, p_value);
+ return true;
+ }
+ } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
+ // Polygons.
+ int polygon_index = components[1].trim_prefix("polygon_").to_int();
+ ERR_FAIL_COND_V(polygon_index < 0, false);
if (layer_index >= occluders.size()) {
if (tile_set) {
@@ -6609,8 +6688,16 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
occluders.resize(layer_index + 1);
}
}
- set_occluder(layer_index, polygon);
- return true;
+
+ if (polygon_index >= occluders[layer_index].polygons.size()) {
+ occluders.write[layer_index].polygons.resize(polygon_index + 1);
+ }
+
+ if (components[2] == "polygon") {
+ Ref polygon = p_value;
+ set_occluder_polygon(layer_index, polygon_index, polygon);
+ return true;
+ }
}
} else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
// Physics layers.
@@ -6638,6 +6725,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
+ // Polygons.
int polygon_index = components[1].trim_prefix("polygon_").to_int();
ERR_FAIL_COND_V(polygon_index < 0, false);
@@ -6724,16 +6812,36 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const {
Vector components = String(p_name).split("/", true, 2);
if (tile_set) {
- if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
+ if (components.size() >= 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
ERR_FAIL_COND_V(layer_index < 0, false);
if (layer_index >= occluders.size()) {
return false;
}
- if (components[1] == "polygon") {
- r_ret = get_occluder(layer_index);
- return true;
+ if (components.size() == 2) {
+ if (components[1] == "polygon") {
+ // Kept for compatibility.
+ if (occluders[layer_index].polygons.is_empty()) {
+ return false;
+ }
+ r_ret = get_occluder_polygon(layer_index, 0);
+ return true;
+ } else if (components[1] == "polygons_count") {
+ r_ret = get_occluder_polygons_count(layer_index);
+ return true;
+ }
+ } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
+ // Polygons.
+ int polygon_index = components[1].trim_prefix("polygon_").to_int();
+ ERR_FAIL_COND_V(polygon_index < 0, false);
+ if (polygon_index >= occluders[layer_index].polygons.size()) {
+ return false;
+ }
+ if (components[2] == "polygon") {
+ r_ret = get_occluder_polygon(layer_index, polygon_index);
+ return true;
+ }
}
} else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
// Physics layers.
@@ -6813,12 +6921,15 @@ void TileData::_get_property_list(List *p_list) const {
// Occlusion layers.
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int i = 0; i < occluders.size(); i++) {
- // occlusion_layer_%d/polygon
- property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
- if (occluders[i].occluder.is_null()) {
- property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/%s", i, PNAME("polygons_count")), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ for (int j = 0; j < occluders[i].polygons.size(); j++) {
+ // occlusion_layer_%d/polygon_%d/polygon
+ property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/polygon_%d/%s", i, j, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
+ if (occluders[i].polygons[j].occluder_polygon.is_null()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
}
- p_list->push_back(property_info);
}
// Physics layers.
@@ -6923,8 +7034,17 @@ void TileData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileData::set_y_sort_origin);
ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin);
+ ClassDB::bind_method(D_METHOD("set_occluder_polygons_count", "layer_id", "polygons_count"), &TileData::set_occluder_polygons_count);
+ ClassDB::bind_method(D_METHOD("get_occluder_polygons_count", "layer_id"), &TileData::get_occluder_polygons_count);
+ ClassDB::bind_method(D_METHOD("add_occluder_polygon", "layer_id"), &TileData::add_occluder_polygon);
+ ClassDB::bind_method(D_METHOD("remove_occluder_polygon", "layer_id", "polygon_index"), &TileData::remove_occluder_polygon);
+ ClassDB::bind_method(D_METHOD("set_occluder_polygon", "layer_id", "polygon_index", "polygon"), &TileData::set_occluder_polygon);
+ ClassDB::bind_method(D_METHOD("get_occluder_polygon", "layer_id", "polygon_index", "flip_h", "flip_v", "transpose"), &TileData::get_occluder_polygon, DEFVAL(false), DEFVAL(false), DEFVAL(false));
+
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder);
ClassDB::bind_method(D_METHOD("get_occluder", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_occluder, DEFVAL(false), DEFVAL(false), DEFVAL(false));
+#endif // DISABLE_DEPRECATED
// Physics.
ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer_id", "velocity"), &TileData::set_constant_linear_velocity);
diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h
index 51df972c8d3..931495d0208 100644
--- a/scene/resources/2d/tile_set.h
+++ b/scene/resources/2d/tile_set.h
@@ -841,8 +841,11 @@ private:
int z_index = 0;
int y_sort_origin = 0;
struct OcclusionLayerTileData {
- Ref occluder;
- mutable HashMap> transformed_occluders;
+ struct PolygonOccluderTileData {
+ Ref occluder_polygon;
+ mutable HashMap> transformed_polygon_occluders;
+ };
+ Vector polygons;
};
Vector occluders;
@@ -941,8 +944,17 @@ public:
void set_y_sort_origin(int p_y_sort_origin);
int get_y_sort_origin() const;
+#ifndef DISABLE_DEPRECATED
void set_occluder(int p_layer_id, Ref p_occluder_polygon);
Ref get_occluder(int p_layer_id, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const;
+#endif // DISABLE_DEPRECATED
+
+ void set_occluder_polygons_count(int p_layer_id, int p_polygons_count);
+ int get_occluder_polygons_count(int p_layer_id) const;
+ void add_occluder_polygon(int p_layer_id);
+ void remove_occluder_polygon(int p_layer_id, int p_polygon_index);
+ void set_occluder_polygon(int p_layer_id, int p_polygon_index, const Ref &p_occluder_polygon);
+ Ref get_occluder_polygon(int p_layer_id, int p_polygon_index, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const;
// Physics
void set_constant_linear_velocity(int p_layer_id, const Vector2 &p_velocity);