diff options
Diffstat (limited to 'scene/2d')
-rw-r--r-- | scene/2d/navigation_agent_2d.cpp | 49 | ||||
-rw-r--r-- | scene/2d/navigation_agent_2d.h | 2 | ||||
-rw-r--r-- | scene/2d/navigation_region_2d.cpp | 31 | ||||
-rw-r--r-- | scene/2d/navigation_region_2d.h | 9 | ||||
-rw-r--r-- | scene/2d/node_2d.cpp | 56 | ||||
-rw-r--r-- | scene/2d/node_2d.h | 4 | ||||
-rw-r--r-- | scene/2d/visible_on_screen_notifier_2d.cpp | 1 |
7 files changed, 128 insertions, 24 deletions
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 00082b321e..80d60dca17 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -96,16 +96,30 @@ void NavigationAgent2D::_bind_methods() { void NavigationAgent2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - agent_parent = Object::cast_to<Node2D>(get_parent()); - if (agent_parent != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - set_avoidance_enabled(avoidance_enabled); - } + case NOTIFICATION_POST_ENTER_TREE: { + // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready. + // cannot use READY as ready does not get called if Node is readded to SceneTree + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; + case NOTIFICATION_PARENTED: { + if (is_inside_tree() && (get_parent() != agent_parent)) { + // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around + // PARENTED notification fires also when Node is added in scripts to a parent + // this would spam transforms fails and world fails while Node is outside SceneTree + // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } + } break; + + case NOTIFICATION_UNPARENTED: { + // if agent has no parent no point in processing it until reparented + set_agent_parent(nullptr); + set_physics_process_internal(false); + } break; + case NOTIFICATION_PAUSED: { if (agent_parent && !agent_parent->can_process()) { map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid()); @@ -133,7 +147,11 @@ void NavigationAgent2D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { - NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + if (avoidance_enabled) { + // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding + // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used + NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + } _check_distance_to_target(); } } break; @@ -167,6 +185,21 @@ bool NavigationAgent2D::get_avoidance_enabled() const { return avoidance_enabled; } +void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { + // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map + NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) { + // place agent on navigation map first or else the RVO agent callback creation fails silently later + agent_parent = Object::cast_to<Node2D>(p_agent_parent); + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); + // create new avoidance callback if enabled + set_avoidance_enabled(avoidance_enabled); + } else { + agent_parent = nullptr; + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 5ab4cdba5d..c9983119d0 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -82,6 +82,8 @@ public: void set_avoidance_enabled(bool p_enabled); bool get_avoidance_enabled() const; + void set_agent_parent(Node *p_agent_parent); + void set_navigable_layers(uint32_t p_layers); uint32_t get_navigable_layers() const; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 260faf1d68..6f3222f27e 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -331,6 +331,7 @@ void NavigationPolygon::_bind_methods() { 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); @@ -387,6 +388,26 @@ uint32_t NavigationRegion2D::get_layers() const { return NavigationServer2D::get_singleton()->region_get_layers(region); } +void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + enter_cost = MAX(p_enter_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost); +} + +real_t NavigationRegion2D::get_enter_cost() const { + return enter_cost; +} + +void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + travel_cost = MAX(p_travel_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, travel_cost); +} + +real_t NavigationRegion2D::get_travel_cost() const { + return travel_cost; +} + RID NavigationRegion2D::get_region_rid() const { return region; } @@ -543,16 +564,26 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid); + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion2D::get_enter_cost); + + 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); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", 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, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_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"); } NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); + NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); } NavigationRegion2D::~NavigationRegion2D() { diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 3c4a4e81d9..31574749f7 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -98,6 +98,9 @@ class NavigationRegion2D : public Node2D { RID region; Ref<NavigationPolygon> navpoly; + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; + void _navpoly_changed(); void _map_changed(RID p_RID); @@ -119,6 +122,12 @@ public: RID get_region_rid() const; + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const; + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const; + void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); Ref<NavigationPolygon> get_navigation_polygon() const; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 2ed5ef905a..6fa18d393e 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -244,9 +244,9 @@ Point2 Node2D::get_global_position() const { } void Node2D::set_global_position(const Point2 &p_pos) { - CanvasItem *pi = get_parent_item(); - if (pi) { - Transform2D inv = pi->get_global_transform().affine_inverse(); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D inv = parent->get_global_transform().affine_inverse(); set_position(inv.xform(p_pos)); } else { set_position(p_pos); @@ -257,25 +257,48 @@ real_t Node2D::get_global_rotation() const { return get_global_transform().get_rotation(); } -void Node2D::set_global_rotation(real_t p_radians) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const real_t parent_global_rot = pi->get_global_transform().get_rotation(); - set_rotation(p_radians - parent_global_rot); +real_t Node2D::get_global_skew() const { + return get_global_transform().get_skew(); +} + +void Node2D::set_global_rotation(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_rotation(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_rotation(new_transform.get_rotation()); } else { set_rotation(p_radians); } } +void Node2D::set_global_skew(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_skew(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_skew(new_transform.get_skew()); + } else { + set_skew(p_radians); + } +} + Size2 Node2D::get_global_scale() const { return get_global_transform().get_scale(); } void Node2D::set_global_scale(const Size2 &p_scale) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const Size2 parent_global_scale = pi->get_global_transform().get_scale(); - set_scale(p_scale / parent_global_scale); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_scale(p_scale); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_scale(new_transform.get_scale()); } else { set_scale(p_scale); } @@ -295,9 +318,9 @@ void Node2D::set_transform(const Transform2D &p_transform) { } void Node2D::set_global_transform(const Transform2D &p_transform) { - CanvasItem *pi = get_parent_item(); - if (pi) { - set_transform(pi->get_global_transform().affine_inverse() * p_transform); + CanvasItem *parent = get_parent_item(); + if (parent) { + set_transform(parent->get_global_transform().affine_inverse() * p_transform); } else { set_transform(p_transform); } @@ -388,6 +411,8 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position); ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_skew", "radians"), &Node2D::set_global_skew); + ClassDB::bind_method(D_METHOD("get_global_skew"), &Node2D::get_global_skew); ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale); ClassDB::bind_method(D_METHOD("get_global_scale"), &Node2D::get_global_scale); @@ -421,6 +446,7 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); ADD_GROUP("Ordering", ""); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 69d14f82ad..473c34768f 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -92,12 +92,14 @@ public: Point2 get_global_position() const; real_t get_global_rotation() const; + real_t get_global_skew() const; Size2 get_global_scale() const; void set_transform(const Transform2D &p_transform); void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); - void set_global_rotation(real_t p_radians); + void set_global_rotation(const real_t p_radians); + void set_global_skew(const real_t p_radians); void set_global_scale(const Size2 &p_scale); void set_z_index(int p_z); diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index 33dd737416..1971dc1240 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -66,6 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { if (is_inside_tree()) { RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); } + update(); } Rect2 VisibleOnScreenNotifier2D::get_rect() const { |