Implement pause-aware picking
This changes the way 2D & 3D physics picking behaves in relation to pause: - When pause is set, every collision object that is hovered or captured (3D only) is released from that condition, getting the relevant mouse-exit callback., unless its pause mode makes it immune from pause. - During the pause. picking only considers collision objects immune from pause, sending input events and enter/exit callbacks to them as expected. - When pause is left, nothing happens. This is a big difference with the classic behavior, which at this point would process all the input events that have been queued against the current state of the 2D/3D world (in other words, checking them against the current position of the objects instead of those at the time of the events).
This commit is contained in:
parent
89a43d9c2e
commit
a63996ac95
@ -409,6 +409,7 @@ bool SceneTree::physics_process(float p_time) {
|
||||
emit_signal("physics_frame");
|
||||
|
||||
_notify_group_pause("physics_process_internal", Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
|
||||
call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_process_picking");
|
||||
_notify_group_pause("physics_process", Node::NOTIFICATION_PHYSICS_PROCESS);
|
||||
_flush_ugc();
|
||||
MessageQueue::get_singleton()->flush(); //small little hack
|
||||
|
@ -568,8 +568,38 @@ void Viewport::_notification(int p_what) {
|
||||
|
||||
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_WM_MOUSE_EXIT: {
|
||||
_drop_physics_mouseover();
|
||||
|
||||
// Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not
|
||||
// drop the gui mouseover here, as a scrollbar may be dragged while the
|
||||
// mouse is outside the window (without the window having lost focus).
|
||||
// See bug #39634
|
||||
} break;
|
||||
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
||||
_drop_physics_mouseover();
|
||||
|
||||
if (gui.mouse_focus && !gui.forced_mouse_focus) {
|
||||
_drop_mouse_focus();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::_process_picking() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
}
|
||||
if (!physics_object_picking) {
|
||||
return;
|
||||
}
|
||||
if (to_screen_rect != Rect2i() && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
|
||||
return;
|
||||
}
|
||||
|
||||
_drop_physics_mouseover(true);
|
||||
|
||||
if (physics_object_picking && (to_screen_rect == Rect2i() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
|
||||
#ifndef _3D_DISABLED
|
||||
Vector2 last_pos(1e20, 1e20);
|
||||
CollisionObject3D *last_object = nullptr;
|
||||
@ -700,7 +730,7 @@ void Viewport::_notification(int p_what) {
|
||||
for (int i = 0; i < rc; i++) {
|
||||
if (res[i].collider_id.is_valid() && res[i].collider) {
|
||||
CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
|
||||
if (co) {
|
||||
if (co && co->can_process()) {
|
||||
bool send_event = true;
|
||||
if (is_mouse) {
|
||||
Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id);
|
||||
@ -788,7 +818,7 @@ void Viewport::_notification(int p_what) {
|
||||
ObjectID new_collider;
|
||||
if (col) {
|
||||
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
|
||||
if (co) {
|
||||
if (co && co->can_process()) {
|
||||
_collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
|
||||
last_object = co;
|
||||
last_id = result.collider_id;
|
||||
@ -823,25 +853,6 @@ void Viewport::_notification(int p_what) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_WM_MOUSE_EXIT: {
|
||||
_drop_physics_mouseover();
|
||||
|
||||
// Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not
|
||||
// drop the gui mouseover here, as a scrollbar may be dragged while the
|
||||
// mouse is outside the window (without the window having lost focus).
|
||||
// See bug #39634
|
||||
} break;
|
||||
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
||||
_drop_physics_mouseover();
|
||||
|
||||
if (gui.mouse_focus && !gui.forced_mouse_focus) {
|
||||
_drop_mouse_focus();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
RID Viewport::get_viewport_rid() const {
|
||||
@ -2582,28 +2593,41 @@ void Viewport::_drop_mouse_focus() {
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::_drop_physics_mouseover() {
|
||||
void Viewport::_drop_physics_mouseover(bool p_paused_only) {
|
||||
physics_has_last_mousepos = false;
|
||||
|
||||
while (physics_2d_mouseover.size()) {
|
||||
Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key());
|
||||
List<Map<ObjectID, uint64_t>::Element *> to_erase;
|
||||
|
||||
for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) {
|
||||
Object *o = ObjectDB::get_instance(E->key());
|
||||
if (o) {
|
||||
CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
|
||||
co->_mouse_exit();
|
||||
if (co) {
|
||||
if (p_paused_only && co->can_process()) {
|
||||
continue;
|
||||
}
|
||||
physics_2d_mouseover.erase(physics_2d_mouseover.front());
|
||||
co->_mouse_exit();
|
||||
to_erase.push_back(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (to_erase.size()) {
|
||||
physics_2d_mouseover.erase(to_erase.front()->get());
|
||||
to_erase.pop_front();
|
||||
}
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
if (physics_object_over.is_valid()) {
|
||||
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
|
||||
if (co) {
|
||||
if (!(p_paused_only && co->can_process())) {
|
||||
co->_mouse_exit();
|
||||
}
|
||||
}
|
||||
|
||||
physics_object_over = ObjectID();
|
||||
physics_object_capture = ObjectID();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3529,6 +3553,8 @@ void Viewport::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_lod_threshold", "pixels"), &Viewport::set_lod_threshold);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_threshold"), &Viewport::get_lod_threshold);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
|
||||
|
@ -450,7 +450,7 @@ private:
|
||||
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
|
||||
|
||||
void _drop_mouse_focus();
|
||||
void _drop_physics_mouseover();
|
||||
void _drop_physics_mouseover(bool p_paused_only = false);
|
||||
|
||||
void _update_canvas_items(Node *p_node);
|
||||
|
||||
@ -479,6 +479,7 @@ protected:
|
||||
bool _is_size_allocated() const;
|
||||
|
||||
void _notification(int p_what);
|
||||
void _process_picking();
|
||||
static void _bind_methods();
|
||||
virtual void _validate_property(PropertyInfo &property) const override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user