Skip to content

Commit 7fef538

Browse files
committed
Merge pull request godotengine#91464 from groud/fix_tilemap_layer_navmesh_baking
Fix TileMapLayer navmesh baking
2 parents 5ea3f0b + 23b9a9f commit 7fef538

File tree

2 files changed

+73
-104
lines changed

2 files changed

+73
-104
lines changed

modules/navigation/2d/nav_mesh_generator_2d.cpp

Lines changed: 72 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
243243
generator_parse_multimeshinstance2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
244244
generator_parse_polygon2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
245245
generator_parse_staticbody2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
246-
generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node);
246+
generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, p_node);
247247
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);
248248

249249
generator_rid_rwlock.read_lock();
@@ -259,6 +259,14 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
259259
for (int i = 0; i < p_node->get_child_count(); i++) {
260260
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
261261
}
262+
} else if (Object::cast_to<TileMap>(p_node)) {
263+
// Special case for TileMap, so that internal layer get parsed even if p_recurse_children is false.
264+
for (int i = 0; i < p_node->get_child_count(); i++) {
265+
TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node->get_child(i));
266+
if (tile_map_layer->get_index_in_tile_map() >= 0) {
267+
generator_parse_tile_map_layer_node(p_navigation_mesh, p_source_geometry_data, tile_map_layer);
268+
}
269+
}
262270
}
263271
}
264272

@@ -580,141 +588,102 @@ void NavMeshGenerator2D::generator_parse_staticbody2d_node(const Ref<NavigationP
580588
}
581589
}
582590

583-
void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
584-
TileMap *tilemap = Object::cast_to<TileMap>(p_node);
585-
586-
if (tilemap == nullptr) {
591+
void NavMeshGenerator2D::generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
592+
TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_node);
593+
if (tile_map_layer == nullptr) {
587594
return;
588595
}
589596

590-
NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
591-
uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
592-
593-
if (tilemap->get_layers_count() <= 0) {
594-
return;
595-
}
596-
597-
Ref<TileSet> tile_set = tilemap->get_tileset();
597+
Ref<TileSet> tile_set = tile_map_layer->get_tile_set();
598598
if (!tile_set.is_valid()) {
599599
return;
600600
}
601601

602602
int physics_layers_count = tile_set->get_physics_layers_count();
603603
int navigation_layers_count = tile_set->get_navigation_layers_count();
604-
605604
if (physics_layers_count <= 0 && navigation_layers_count <= 0) {
606605
return;
607606
}
608607

609-
HashSet<Vector2i> cells_with_navigation_polygon;
610-
HashSet<Vector2i> cells_with_collision_polygon;
608+
NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
609+
uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
610+
611+
const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tile_map_layer->get_global_transform();
611612

612-
const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
613+
TypedArray<Vector2i> used_cells = tile_map_layer->get_used_cells();
614+
for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
615+
const Vector2i &cell = used_cells[used_cell_index];
613616

614-
#ifdef DEBUG_ENABLED
615-
int error_print_counter = 0;
616-
int error_print_max = 10;
617-
#endif // DEBUG_ENABLED
617+
const TileData *tile_data = tile_map_layer->get_cell_tile_data(cell);
618+
if (tile_data == nullptr) {
619+
continue;
620+
}
618621

619-
for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) {
620-
TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
622+
// Transform flags.
623+
const int alternative_id = tile_map_layer->get_cell_alternative_tile(cell);
624+
bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
625+
bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
626+
bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
627+
628+
Transform2D tile_transform;
629+
tile_transform.set_origin(tile_map_layer->map_to_local(cell));
630+
631+
const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
632+
633+
// Parse traversable polygons.
634+
for (int navigation_layer = 0; navigation_layer < navigation_layers_count; navigation_layer++) {
635+
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer, flip_h, flip_v, transpose);
636+
if (navigation_polygon.is_valid()) {
637+
for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
638+
const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
639+
if (navigation_polygon_outline.is_empty()) {
640+
continue;
641+
}
621642

622-
for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
623-
const Vector2i &cell = used_cells[used_cell_index];
643+
Vector<Vector2> traversable_outline;
644+
traversable_outline.resize(navigation_polygon_outline.size());
624645

625-
const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
626-
if (tile_data == nullptr) {
627-
continue;
628-
}
646+
const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
647+
Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
629648

630-
// Transform flags.
631-
const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
632-
bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
633-
bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
634-
bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
635-
636-
Transform2D tile_transform;
637-
tile_transform.set_origin(tilemap->map_to_local(cell));
638-
639-
const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
640-
641-
if (navigation_layers_count > 0) {
642-
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
643-
if (navigation_polygon.is_valid()) {
644-
if (cells_with_navigation_polygon.has(cell)) {
645-
#ifdef DEBUG_ENABLED
646-
error_print_counter++;
647-
if (error_print_counter <= error_print_max) {
648-
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));
649-
}
650-
#endif // DEBUG_ENABLED
651-
} else {
652-
cells_with_navigation_polygon.insert(cell);
653-
654-
for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
655-
const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
656-
if (navigation_polygon_outline.size() == 0) {
657-
continue;
658-
}
659-
660-
Vector<Vector2> traversable_outline;
661-
traversable_outline.resize(navigation_polygon_outline.size());
662-
663-
const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
664-
Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
665-
666-
for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
667-
traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
668-
}
669-
670-
p_source_geometry_data->_add_traversable_outline(traversable_outline);
671-
}
649+
for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
650+
traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
672651
}
652+
653+
p_source_geometry_data->_add_traversable_outline(traversable_outline);
673654
}
674655
}
656+
}
675657

676-
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)) {
677-
if (cells_with_collision_polygon.has(cell)) {
678-
#ifdef DEBUG_ENABLED
679-
error_print_counter++;
680-
if (error_print_counter <= error_print_max) {
681-
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));
658+
// Parse obstacles.
659+
for (int physics_layer = 0; physics_layer < physics_layers_count; physics_layer++) {
660+
if ((parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) &&
661+
(tile_set->get_physics_layer_collision_layer(physics_layer) & parsed_collision_mask)) {
662+
for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(physics_layer); collision_polygon_index++) {
663+
PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(physics_layer, collision_polygon_index);
664+
if (collision_polygon_points.is_empty()) {
665+
continue;
682666
}
683-
#endif // DEBUG_ENABLED
684-
} else {
685-
cells_with_collision_polygon.insert(cell);
686-
687-
for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
688-
PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
689-
if (collision_polygon_points.size() == 0) {
690-
continue;
691-
}
692-
693-
if (flip_h || flip_v || transpose) {
694-
collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
695-
}
696667

697-
Vector<Vector2> obstruction_outline;
698-
obstruction_outline.resize(collision_polygon_points.size());
668+
if (flip_h || flip_v || transpose) {
669+
collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
670+
}
699671

700-
const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
701-
Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
672+
Vector<Vector2> obstruction_outline;
673+
obstruction_outline.resize(collision_polygon_points.size());
702674

703-
for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
704-
obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
705-
}
675+
const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
676+
Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
706677

707-
p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
678+
for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
679+
obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
708680
}
681+
682+
p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
709683
}
710684
}
711685
}
712686
}
713-
#ifdef DEBUG_ENABLED
714-
if (error_print_counter > error_print_max) {
715-
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));
716-
}
717-
#endif // DEBUG_ENABLED
718687
}
719688

720689
void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {

modules/navigation/2d/nav_mesh_generator_2d.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class NavMeshGenerator2D : public Object {
8989
static void generator_parse_multimeshinstance2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
9090
static void generator_parse_polygon2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
9191
static void generator_parse_staticbody2d_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
92-
static void generator_parse_tilemap_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
92+
static void generator_parse_tile_map_layer_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
9393
static void generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node);
9494

9595
static bool generator_emit_callback(const Callable &p_callback);

0 commit comments

Comments
 (0)