summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Roudière <gilles.roudiere@gmail.com>2024-05-02 17:35:36 +0200
committerGilles Roudière <gilles.roudiere@gmail.com>2024-05-02 18:06:23 +0200
commit23b9a9f2ded161fddc76f0ba576edd4b3c8afffd (patch)
treed95bb28c775763ef93322ce827ec37c5fae24ab0
parent06d105e268ace265809ae3fac2f17ccea9ff88dd (diff)
downloadredot-engine-23b9a9f2ded161fddc76f0ba576edd4b3c8afffd.tar.gz
Fix TileMapLayer navmesh baking
-rw-r--r--modules/navigation/2d/nav_mesh_generator_2d.cpp175
-rw-r--r--modules/navigation/2d/nav_mesh_generator_2d.h2
2 files changed, 73 insertions, 104 deletions
diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp
index 15a645816c..2198158f9c 100644
--- a/modules/navigation/2d/nav_mesh_generator_2d.cpp
+++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp
@@ -243,7 +243,7 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
generator_parse_multimeshinstance2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
generator_parse_polygon2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
generator_parse_staticbody2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
- generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node);
+ generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, p_node);
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);
generator_rid_rwlock.read_lock();
@@ -259,6 +259,14 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
for (int i = 0; i < p_node->get_child_count(); i++) {
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
}
+ } else if (Object::cast_to<TileMap>(p_node)) {
+ // Special case for TileMap, so that internal layer get parsed even if p_recurse_children is false.
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node->get_child(i));
+ if (tile_map_layer->get_index_in_tile_map() >= 0) {
+ generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, tile_map_layer);
+ }
+ }
}
}
@@ -580,141 +588,102 @@ void NavMeshGenerator2D::generator_parse_staticbody2d_node(const Ref<NavigationP
}
}
-void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
- TileMap *tilemap = Object::cast_to<TileMap>(p_node);
-
- if (tilemap == nullptr) {
+void NavMeshGenerator2D::generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
+ TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node);
+ if (tile_map_layer == nullptr) {
return;
}
- NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
- uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
-
- if (tilemap->get_layers_count() <= 0) {
- return;
- }
-
- Ref<TileSet> tile_set = tilemap->get_tileset();
+ Ref<TileSet> tile_set = tile_map_layer->get_tile_set();
if (!tile_set.is_valid()) {
return;
}
int physics_layers_count = tile_set->get_physics_layers_count();
int navigation_layers_count = tile_set->get_navigation_layers_count();
-
if (physics_layers_count <= 0 && navigation_layers_count <= 0) {
return;
}
- HashSet<Vector2i> cells_with_navigation_polygon;
- HashSet<Vector2i> cells_with_collision_polygon;
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
+
+ const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tile_map_layer->get_global_transform();
- const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
+ TypedArray<Vector2i> used_cells = tile_map_layer->get_used_cells();
+ for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
+ const Vector2i &cell = used_cells[used_cell_index];
-#ifdef DEBUG_ENABLED
- int error_print_counter = 0;
- int error_print_max = 10;
-#endif // DEBUG_ENABLED
+ const TileData *tile_data = tile_map_layer->get_cell_tile_data(cell);
+ if (tile_data == nullptr) {
+ continue;
+ }
- for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) {
- TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
+ // Transform flags.
+ const int alternative_id = tile_map_layer->get_cell_alternative_tile(cell);
+ bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
+ bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
+ bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+
+ Transform2D tile_transform;
+ tile_transform.set_origin(tile_map_layer->map_to_local(cell));
+
+ const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+
+ // Parse traversable polygons.
+ for (int navigation_layer = 0; navigation_layer < navigation_layers_count; navigation_layer++) {
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer, flip_h, flip_v, transpose);
+ if (navigation_polygon.is_valid()) {
+ for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
+ const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
+ if (navigation_polygon_outline.is_empty()) {
+ continue;
+ }
- for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
- const Vector2i &cell = used_cells[used_cell_index];
+ Vector<Vector2> traversable_outline;
+ traversable_outline.resize(navigation_polygon_outline.size());
- const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
- if (tile_data == nullptr) {
- continue;
- }
+ const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
+ Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
- // Transform flags.
- const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
- bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
- bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
- bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
-
- Transform2D tile_transform;
- tile_transform.set_origin(tilemap->map_to_local(cell));
-
- const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
-
- if (navigation_layers_count > 0) {
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
- if (navigation_polygon.is_valid()) {
- if (cells_with_navigation_polygon.has(cell)) {
-#ifdef DEBUG_ENABLED
- error_print_counter++;
- if (error_print_counter <= error_print_max) {
- WARN_PRINT(vformat("TileMap navigation mesh baking error. The TileMap cell key Vector2i(%s, %s) has navigation mesh from 2 or more different TileMap layers assigned. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
- }
-#endif // DEBUG_ENABLED
- } else {
- cells_with_navigation_polygon.insert(cell);
-
- for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
- const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
- if (navigation_polygon_outline.size() == 0) {
- continue;
- }
-
- Vector<Vector2> traversable_outline;
- traversable_outline.resize(navigation_polygon_outline.size());
-
- const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
- Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
-
- for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
- traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
- }
-
- p_source_geometry_data->_add_traversable_outline(traversable_outline);
- }
+ for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
+ traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
}
+
+ p_source_geometry_data->_add_traversable_outline(traversable_outline);
}
}
+ }
- if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
- if (cells_with_collision_polygon.has(cell)) {
-#ifdef DEBUG_ENABLED
- error_print_counter++;
- if (error_print_counter <= error_print_max) {
- WARN_PRINT(vformat("TileMap navigation mesh baking error. The cell key Vector2i(%s, %s) has collision polygons from 2 or more different TileMap layers assigned that all match the parsed collision mask. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
+ // Parse obstacles.
+ for (int physics_layer = 0; physics_layer < physics_layers_count; physics_layer++) {
+ if ((parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) &&
+ (tile_set->get_physics_layer_collision_layer(physics_layer) & parsed_collision_mask)) {
+ for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(physics_layer); collision_polygon_index++) {
+ PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(physics_layer, collision_polygon_index);
+ if (collision_polygon_points.is_empty()) {
+ continue;
}
-#endif // DEBUG_ENABLED
- } else {
- cells_with_collision_polygon.insert(cell);
-
- for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
- PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
- if (collision_polygon_points.size() == 0) {
- continue;
- }
-
- if (flip_h || flip_v || transpose) {
- collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
- }
- Vector<Vector2> obstruction_outline;
- obstruction_outline.resize(collision_polygon_points.size());
+ if (flip_h || flip_v || transpose) {
+ collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
+ }
- const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
- Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
+ Vector<Vector2> obstruction_outline;
+ obstruction_outline.resize(collision_polygon_points.size());
- for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
- obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
- }
+ const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
+ Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
- p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
+ for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
+ obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
}
+
+ p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
}
}
}
}
-#ifdef DEBUG_ENABLED
- if (error_print_counter > error_print_max) {
- ERR_PRINT(vformat("TileMap navigation mesh baking error. A total of %s cells with navigation or collision polygons from 2 or more different TileMap layers overlap. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", error_print_counter));
- }
-#endif // DEBUG_ENABLED
}
void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
diff --git a/modules/navigation/2d/nav_mesh_generator_2d.h b/modules/navigation/2d/nav_mesh_generator_2d.h
index 235a84d548..d5f9694242 100644
--- a/modules/navigation/2d/nav_mesh_generator_2d.h
+++ b/modules/navigation/2d/nav_mesh_generator_2d.h
@@ -89,7 +89,7 @@ class NavMeshGenerator2D : public Object {
static void generator_parse_multimeshinstance2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
static void generator_parse_polygon2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
static void generator_parse_staticbody2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
- static void generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
+ static void generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
static void generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
static bool generator_emit_callback(const Callable &p_callback);