Skip to content

Commit

Permalink
Implement navigation obstacle support for LayeredTileMapLayers.
Browse files Browse the repository at this point in the history
  • Loading branch information
Relintai committed May 11, 2024
1 parent 01342ca commit d59353d
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 10 deletions.
139 changes: 129 additions & 10 deletions modules/layered_tile_map/layered_tile_map_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,19 @@ void LayeredTileMapLayer::_rendering_update(bool p_force_cleanup) {
// Check if anything changed that might change the quadrant shape.
// If so, recreate everything.
bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] ||
((is_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED])) ||
dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] ||
dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] ||
dirty.flags[DIRTY_FLAGS_TILE_SET]
((is_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED])) ||
dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] ||
dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] ||
dirty.flags[DIRTY_FLAGS_TILE_SET]

#ifdef MODULE_VERTEX_LIGHTS_2D_ENABLED
|| dirty.flags[DIRTY_FLAGS_LAYER_VERTEX_LIGHTS]
|| dirty.flags[DIRTY_FLAGS_LAYER_VERTEX_LIGHTS]
#endif

#ifdef MODULE_FASTNOISE_ENABLED
|| dirty.flags[DIRTY_FLAGS_LAYER_RAO]
|| dirty.flags[DIRTY_FLAGS_LAYER_RAO]
#endif
);
);

// Free all quadrants.
if (forced_cleanup || quandrant_shape_changed) {
Expand Down Expand Up @@ -1071,6 +1071,13 @@ void LayeredTileMapLayer::_navigation_notification(int p_what) {
Transform2D tilemap_xform = get_global_transform();
for (HashMap<Vector2i, CellData>::Element *kv = tile_map_layer_data.front(); kv; kv = kv->next) {
const CellData &cell_data = kv->value();

Transform2D tile_transform;
tile_transform.set_origin(tile_set->map_to_local(kv->key()));

Transform2D ctf = tilemap_xform * tile_transform;
Vector2 pos = ctf.xform(Vector2());

// Update navigation regions transform.
for (uint32_t i = 0; i < cell_data.navigation_regions.size(); ++i) {
const RID &region = cell_data.navigation_regions[i];
Expand All @@ -1079,9 +1086,18 @@ void LayeredTileMapLayer::_navigation_notification(int p_what) {
continue;
}

Transform2D tile_transform;
tile_transform.set_origin(tile_set->map_to_local(kv->key()));
Navigation2DServer::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
Navigation2DServer::get_singleton()->region_set_transform(region, ctf);
}

// Update navigation obstacle transform.
for (uint32_t i = 0; i < cell_data.obstacles.size(); ++i) {
const RID &obstacle = cell_data.obstacles[i];

if (!obstacle.is_valid()) {
continue;
}

Navigation2DServer::get_singleton()->obstacle_set_position(obstacle, pos);
}
}
}
Expand All @@ -1099,6 +1115,16 @@ void LayeredTileMapLayer::_navigation_clear_cell(CellData &r_cell_data) {
}
}
r_cell_data.navigation_regions.clear();

// Clear navigation obstacles.
for (uint32_t i = 0; i < r_cell_data.obstacles.size(); i++) {
const RID &obstacle = r_cell_data.obstacles[i];
if (obstacle.is_valid()) {
ns->obstacle_set_map(obstacle, RID());
ns->free(obstacle);
}
}
r_cell_data.obstacles.clear();
}

void LayeredTileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
Expand Down Expand Up @@ -1168,6 +1194,46 @@ void LayeredTileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
}
}

// Free unused obstacles then resize the obstacles array.
for (uint32_t i = tile_set->get_avoidance_layers_count(); i < r_cell_data.obstacles.size(); i++) {
RID &obstacle = r_cell_data.obstacles[i];
if (obstacle.is_valid()) {
ns->obstacle_set_map(obstacle, RID());
ns->free(obstacle);
obstacle = RID();
}
}
r_cell_data.obstacles.resize(tile_set->get_avoidance_layers_count());

// Create, update or clear obstacles.
for (uint32_t avoidance_layer_index = 0; avoidance_layer_index < r_cell_data.obstacles.size(); avoidance_layer_index++) {
Vector<Vector2> polygon = tile_data->get_transformed_avoidance_polygon(avoidance_layer_index, flip_h, flip_v, transpose);

RID &obstacle = r_cell_data.obstacles[avoidance_layer_index];

if (polygon.size() >= 3) {
// Create or update regions.
Vector2 pos = tile_set->map_to_local(r_cell_data.coords);

if (!obstacle.is_valid()) {
obstacle = ns->obstacle_create();
}

ns->obstacle_set_map(obstacle, navigation_map);
ns->obstacle_set_vertices(obstacle, polygon);
ns->obstacle_set_radius(obstacle, tile_data->get_avoidance_radius(avoidance_layer_index));
ns->obstacle_set_position(obstacle, pos + tile_data->get_avoidance_position(avoidance_layer_index));
ns->obstacle_set_avoidance_layers(obstacle, tile_set->get_avoidance_layer_layers(avoidance_layer_index));
} else {
// Clear region.
if (obstacle.is_valid()) {
ns->obstacle_set_map(obstacle, RID());
ns->free(obstacle);
obstacle = RID();
}
}
}

return;
}
}
Expand Down Expand Up @@ -1277,6 +1343,59 @@ void LayeredTileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item,
}
}
}

if (r_cell_data.obstacles.empty()) {
return;
}

Color pushin_face_color = Navigation2DServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_face_color();
Color pushout_face_color = Navigation2DServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_face_color();
Color pushin_edge_color = Navigation2DServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_edge_color();
Color pushout_edge_color = Navigation2DServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_edge_color();

for (int layer_index = 0; layer_index < tile_set->get_avoidance_layers_count(); layer_index++) {
bool flip_h = (c.alternative_tile & LayeredTileSetAtlasSource::TRANSFORM_FLIP_H);
bool flip_v = (c.alternative_tile & LayeredTileSetAtlasSource::TRANSFORM_FLIP_V);
bool transpose = (c.alternative_tile & LayeredTileSetAtlasSource::TRANSFORM_TRANSPOSE);

Vector<Vector2> polygon = tile_data->get_transformed_avoidance_polygon(layer_index, flip_h, flip_v, transpose);

if (polygon.size() >= 3) {
bool obstacle_pushes_inward = Geometry::is_polygon_clockwise(polygon);

Color debug_static_obstacle_face_color;

if (obstacle_pushes_inward) {
debug_static_obstacle_face_color = pushin_face_color;
} else {
debug_static_obstacle_face_color = pushout_face_color;
}

Vector<Color> debug_obstacle_polygon_colors;
debug_obstacle_polygon_colors.resize(polygon.size());
debug_obstacle_polygon_colors.fill(debug_static_obstacle_face_color);

RS::get_singleton()->canvas_item_add_polygon(p_canvas_item, polygon, debug_obstacle_polygon_colors);

Color debug_static_obstacle_edge_color;

if (obstacle_pushes_inward) {
debug_static_obstacle_edge_color = pushin_edge_color;
} else {
debug_static_obstacle_edge_color = pushout_edge_color;
}

Vector<Vector2> debug_obstacle_line_vertices = polygon;
debug_obstacle_line_vertices.push_back(debug_obstacle_line_vertices[0]);
debug_obstacle_line_vertices.resize(debug_obstacle_line_vertices.size());

Vector<Color> debug_obstacle_line_colors;
debug_obstacle_line_colors.resize(debug_obstacle_line_vertices.size());
debug_obstacle_line_colors.fill(debug_static_obstacle_edge_color);

RS::get_singleton()->canvas_item_add_polyline(p_canvas_item, debug_obstacle_line_vertices, debug_obstacle_line_colors, 4.0);
}
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions modules/layered_tile_map/layered_tile_map_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ struct CellData {
// Navigation.
LocalVector<RID> navigation_regions;

// Avoidance.
LocalVector<RID> obstacles;

// Scenes.
String scene;

Expand All @@ -154,6 +157,7 @@ struct CellData {
occluders = p_other.occluders;
bodies = p_other.bodies;
navigation_regions = p_other.navigation_regions;
obstacles = p_other.obstacles;
scene = p_other.scene;
runtime_tile_data_cache = p_other.runtime_tile_data_cache;

Expand All @@ -175,6 +179,7 @@ struct CellData {
occluders = p_other.occluders;
bodies = p_other.bodies;
navigation_regions = p_other.navigation_regions;
obstacles = p_other.obstacles;
scene = p_other.scene;
runtime_tile_data_cache = p_other.runtime_tile_data_cache;

Expand Down
33 changes: 33 additions & 0 deletions modules/layered_tile_map/layered_tile_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6807,6 +6807,39 @@ Vector<Vector2> LayeredTileData::get_avoidance_polygon_points(int p_layer_id) co
return avoidance[p_layer_id].polygon;
}

Vector<Vector2> LayeredTileData::get_transformed_avoidance_polygon(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector<Vector2>());

const Vector<Vector2> &polygon = avoidance[p_layer_id].polygon;

const Vector2 *r = polygon.ptr();
int size = polygon.size();

Vector<Vector2> transformed_polygon;
transformed_polygon.resize(polygon.size());

Vector2 *w = transformed_polygon.ptrw();

for (int i = 0; i < size; i++) {
Vector2 v;
if (p_transpose) {
v = Vector2(r[i].y, r[i].x);
} else {
v = r[i];
}

if (p_flip_h) {
v.x *= -1;
}
if (p_flip_v) {
v.y *= -1;
}
w[i] = v;
}

return transformed_polygon;
}

// Misc
void LayeredTileData::set_probability(float p_probability) {
ERR_FAIL_COND(p_probability < 0.0);
Expand Down
2 changes: 2 additions & 0 deletions modules/layered_tile_map/layered_tile_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,8 @@ class LayeredTileData : public Object {
void set_avoidance_polygon_points(int p_layer_id, Vector<Vector2> p_polygon);
Vector<Vector2> get_avoidance_polygon_points(int p_layer_id) const;

Vector<Vector2> get_transformed_avoidance_polygon(int p_layer_id, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const;

// Misc
void set_probability(float p_probability);
float get_probability() const;
Expand Down

0 comments on commit d59353d

Please sign in to comment.