mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-03 01:19:38 +01:00
Implement navigation obstacle support for LayeredTileMapLayers.
This commit is contained in:
parent
01342ca5fd
commit
d59353d48e
@ -217,18 +217,18 @@ void LayeredTileMapLayer::_rendering_update(bool p_force_cleanup) {
|
||||
// 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]
|
||||
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) {
|
||||
@ -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 ®ion = cell_data.navigation_regions[i];
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +134,9 @@ struct CellData {
|
||||
// Navigation.
|
||||
LocalVector<RID> navigation_regions;
|
||||
|
||||
// Avoidance.
|
||||
LocalVector<RID> obstacles;
|
||||
|
||||
// Scenes.
|
||||
String scene;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -1034,6 +1034,8 @@ public:
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user