Fix NavigationAgent reparent issues
Fix NavigationAgent reparent issues
This commit is contained in:
parent
d8b0a8cd29
commit
56fe26b5e0
4 changed files with 87 additions and 17 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -102,18 +102,32 @@ void NavigationAgent3D::_bind_methods() {
|
|||
|
||||
void NavigationAgent3D::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
agent_parent = Object::cast_to<Node3D>(get_parent());
|
||||
if (agent_parent != nullptr) {
|
||||
// place agent on navigation map first or else the RVO agent callback creation fails silently later
|
||||
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->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_EXIT_TREE: {
|
||||
agent_parent = nullptr;
|
||||
set_agent_parent(nullptr);
|
||||
set_physics_process_internal(false);
|
||||
} break;
|
||||
|
||||
|
@ -139,7 +153,11 @@ void NavigationAgent3D::_notification(int p_what) {
|
|||
|
||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
if (agent_parent) {
|
||||
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
|
||||
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
|
||||
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
|
||||
}
|
||||
_check_distance_to_target();
|
||||
}
|
||||
} break;
|
||||
|
@ -174,6 +192,21 @@ bool NavigationAgent3D::get_avoidance_enabled() const {
|
|||
return avoidance_enabled;
|
||||
}
|
||||
|
||||
void NavigationAgent3D::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
|
||||
NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
|
||||
if (Object::cast_to<Node3D>(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<Node3D>(p_agent_parent);
|
||||
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
|
||||
// create new avoidance callback if enabled
|
||||
set_avoidance_enabled(avoidance_enabled);
|
||||
} else {
|
||||
agent_parent = nullptr;
|
||||
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationAgent3D::set_navigable_layers(uint32_t p_layers) {
|
||||
bool layers_changed = navigable_layers != p_layers;
|
||||
navigable_layers = p_layers;
|
||||
|
|
|
@ -84,6 +84,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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue