diff options
Diffstat (limited to 'scene/2d/navigation_region_2d.cpp')
-rw-r--r-- | scene/2d/navigation_region_2d.cpp | 388 |
1 files changed, 44 insertions, 344 deletions
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 6e8ecb13b1..675ef7c780 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -31,331 +31,10 @@ #include "navigation_region_2d.h" #include "core/core_string_names.h" -#include "core/math/geometry_2d.h" -#include "core/os/mutex.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" -#include "thirdparty/misc/polypartition.h" - -#ifdef TOOLS_ENABLED -Rect2 NavigationPolygon::_edit_get_rect() const { - if (rect_cache_dirty) { - item_rect = Rect2(); - bool first = true; - - for (int i = 0; i < outlines.size(); i++) { - const Vector<Vector2> &outline = outlines[i]; - const int outline_size = outline.size(); - if (outline_size < 3) { - continue; - } - const Vector2 *p = outline.ptr(); - for (int j = 0; j < outline_size; j++) { - if (first) { - item_rect = Rect2(p[j], Vector2(0, 0)); - first = false; - } else { - item_rect.expand_to(p[j]); - } - } - } - - rect_cache_dirty = false; - } - return item_rect; -} - -bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - for (int i = 0; i < outlines.size(); i++) { - const Vector<Vector2> &outline = outlines[i]; - const int outline_size = outline.size(); - if (outline_size < 3) { - continue; - } - if (Geometry2D::is_point_in_polygon(p_point, Variant(outline))) { - return true; - } - } - return false; -} -#endif - -void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - vertices = p_vertices; - rect_cache_dirty = true; -} - -Vector<Vector2> NavigationPolygon::get_vertices() const { - return vertices; -} - -void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array) { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - polygons.resize(p_array.size()); - for (int i = 0; i < p_array.size(); i++) { - polygons.write[i].indices = p_array[i]; - } -} - -TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const { - TypedArray<Vector<int32_t>> ret; - ret.resize(polygons.size()); - for (int i = 0; i < ret.size(); i++) { - ret[i] = polygons[i].indices; - } - - return ret; -} - -void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array) { - outlines.resize(p_array.size()); - for (int i = 0; i < p_array.size(); i++) { - outlines.write[i] = p_array[i]; - } - rect_cache_dirty = true; -} - -TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const { - TypedArray<Vector<Vector2>> ret; - ret.resize(outlines.size()); - for (int i = 0; i < ret.size(); i++) { - ret[i] = outlines[i]; - } - - return ret; -} - -void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) { - Polygon polygon; - polygon.indices = p_polygon; - polygons.push_back(polygon); - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } -} - -void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) { - outlines.insert(p_index, p_outline); - rect_cache_dirty = true; -} - -int NavigationPolygon::get_polygon_count() const { - return polygons.size(); -} - -Vector<int> NavigationPolygon::get_polygon(int p_idx) { - ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>()); - return polygons[p_idx].indices; -} - -void NavigationPolygon::clear_polygons() { - polygons.clear(); - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } -} - -Ref<NavigationMesh> NavigationPolygon::get_mesh() { - MutexLock lock(navmesh_generation); - - if (navmesh.is_null()) { - navmesh.instantiate(); - Vector<Vector3> verts; - { - verts.resize(get_vertices().size()); - Vector3 *w = verts.ptrw(); - - const Vector2 *r = get_vertices().ptr(); - - for (int i(0); i < get_vertices().size(); i++) { - w[i] = Vector3(r[i].x, 0.0, r[i].y); - } - } - navmesh->set_vertices(verts); - - for (int i(0); i < get_polygon_count(); i++) { - navmesh->add_polygon(get_polygon(i)); - } - } - - return navmesh; -} - -void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) { - outlines.push_back(p_outline); - rect_cache_dirty = true; -} - -int NavigationPolygon::get_outline_count() const { - return outlines.size(); -} - -void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) { - ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines.write[p_idx] = p_outline; - rect_cache_dirty = true; -} - -void NavigationPolygon::remove_outline(int p_idx) { - ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines.remove_at(p_idx); - rect_cache_dirty = true; -} - -Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>()); - return outlines[p_idx]; -} - -void NavigationPolygon::clear_outlines() { - outlines.clear(); - rect_cache_dirty = true; -} - -void NavigationPolygon::make_polygons_from_outlines() { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - List<TPPLPoly> in_poly, out_poly; - - Vector2 outside_point(-1e10, -1e10); - - for (int i = 0; i < outlines.size(); i++) { - Vector<Vector2> ol = outlines[i]; - int olsize = ol.size(); - if (olsize < 3) { - continue; - } - const Vector2 *r = ol.ptr(); - for (int j = 0; j < olsize; j++) { - outside_point.x = MAX(r[j].x, outside_point.x); - outside_point.y = MAX(r[j].y, outside_point.y); - } - } - - outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues - - for (int i = 0; i < outlines.size(); i++) { - Vector<Vector2> ol = outlines[i]; - int olsize = ol.size(); - if (olsize < 3) { - continue; - } - const Vector2 *r = ol.ptr(); - - int interscount = 0; - //test if this is an outer outline - for (int k = 0; k < outlines.size(); k++) { - if (i == k) { - continue; //no self intersect - } - - Vector<Vector2> ol2 = outlines[k]; - int olsize2 = ol2.size(); - if (olsize2 < 3) { - continue; - } - const Vector2 *r2 = ol2.ptr(); - - for (int l = 0; l < olsize2; l++) { - if (Geometry2D::segment_intersects_segment(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) { - interscount++; - } - } - } - - bool outer = (interscount % 2) == 0; - - TPPLPoly tp; - tp.Init(olsize); - for (int j = 0; j < olsize; j++) { - tp[j] = r[j]; - } - - if (outer) { - tp.SetOrientation(TPPL_ORIENTATION_CCW); - } else { - tp.SetOrientation(TPPL_ORIENTATION_CW); - tp.SetHole(true); - } - - in_poly.push_back(tp); - } - - TPPLPartition tpart; - if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! - ERR_PRINT("NavigationPolygon: Convex partition failed!"); - return; - } - - polygons.clear(); - vertices.clear(); - - HashMap<Vector2, int> points; - for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { - TPPLPoly &tp = I->get(); - - struct Polygon p; - - for (int64_t i = 0; i < tp.GetNumPoints(); i++) { - HashMap<Vector2, int>::Iterator E = points.find(tp[i]); - if (!E) { - E = points.insert(tp[i], vertices.size()); - vertices.push_back(tp[i]); - } - p.indices.push_back(E->value); - } - - polygons.push_back(p); - } - - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void NavigationPolygon::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices); - ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices); - - ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon); - ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count); - ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon); - ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons); - ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh); - - ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline); - ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index); - ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count); - ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline); - ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline); - ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline); - ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines); - ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines); - - ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons); - ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons); - - ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); - ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); - - ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); -} - -///////////////////////////// - void NavigationRegion2D::set_enabled(bool p_enabled) { if (enabled == p_enabled) { return; @@ -458,11 +137,11 @@ RID NavigationRegion2D::get_region_rid() const { #ifdef TOOLS_ENABLED Rect2 NavigationRegion2D::_edit_get_rect() const { - return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2(); + return navigation_polygon.is_valid() ? navigation_polygon->_edit_get_rect() : Rect2(); } bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false; + return navigation_polygon.is_valid() ? navigation_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false; } #endif @@ -488,8 +167,8 @@ void NavigationRegion2D::_notification(int p_what) { case NOTIFICATION_DRAW: { #ifdef DEBUG_ENABLED - if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) { - Vector<Vector2> verts = navpoly->get_vertices(); + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navigation_polygon.is_valid()) { + Vector<Vector2> verts = navigation_polygon->get_vertices(); if (verts.size() < 3) { return; } @@ -504,9 +183,9 @@ void NavigationRegion2D::_notification(int p_what) { RandomPCG rand; - for (int i = 0; i < navpoly->get_polygon_count(); i++) { + for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { // An array of vertices for this polygon. - Vector<int> polygon = navpoly->get_polygon(i); + Vector<int> polygon = navigation_polygon->get_polygon(i); Vector<Vector2> vertices; vertices.resize(polygon.size()); for (int j = 0; j < polygon.size(); j++) { @@ -547,36 +226,36 @@ void NavigationRegion2D::_notification(int p_what) { } } -void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) { - if (p_navpoly == navpoly) { +void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon) { + if (p_navigation_polygon == navigation_polygon) { return; } - if (navpoly.is_valid()) { - navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed)); + if (navigation_polygon.is_valid()) { + navigation_polygon->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed)); } - navpoly = p_navpoly; - NavigationServer2D::get_singleton()->region_set_navpoly(region, p_navpoly); + navigation_polygon = p_navigation_polygon; + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon); - if (navpoly.is_valid()) { - navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed)); + if (navigation_polygon.is_valid()) { + navigation_polygon->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed)); } - _navpoly_changed(); + _navigation_polygon_changed(); update_configuration_warnings(); } Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const { - return navpoly; + return navigation_polygon; } -void NavigationRegion2D::_navpoly_changed() { +void NavigationRegion2D::_navigation_polygon_changed() { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) { queue_redraw(); } - if (navpoly.is_valid()) { - NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); + if (navigation_polygon.is_valid()) { + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon); } } @@ -592,7 +271,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const { PackedStringArray warnings = Node2D::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { - if (!navpoly.is_valid()) { + if (!navigation_polygon.is_valid()) { warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon.")); } } @@ -601,7 +280,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const { } void NavigationRegion2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon); + ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navigation_polygon"), &NavigationRegion2D::set_navigation_polygon); ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon); ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled); @@ -621,18 +300,39 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost); ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost); - ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed); + ClassDB::bind_method(D_METHOD("_navigation_polygon_changed"), &NavigationRegion2D::_navigation_polygon_changed); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_polygon", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); } +#ifndef DISABLE_DEPRECATED +// Compatibility with earlier 4.0 betas. +bool NavigationRegion2D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "navpoly") { + set_navigation_polygon(p_value); + return true; + } + return false; +} + +bool NavigationRegion2D::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "navpoly") { + r_ret = get_navigation_polygon(); + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); + region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id()); NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); |