Fix passive mouse hovering for physics

Currently mouse hovering doesn't update the state, when collision objects
or the camera move.
This PR fixes this problem by taking the mouse position from the viewport
and not from a nonexistent previous event.

Since previous events could potentially be a long time ago, their
modifier-key state might be outdated. This PR fetches the current
status of modifier-keys from `Input`.

These changes allow the removal of some class-variables and making
additional simplifications.
This commit is contained in:
Markus Sauermann 2023-06-08 21:04:38 +02:00
parent e188d61922
commit 543fdc1490
2 changed files with 24 additions and 75 deletions

View File

@ -682,32 +682,31 @@ void Viewport::_process_picking() {
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
if (physics_has_last_mousepos) {
bool has_mouse_event = false;
for (const Ref<InputEvent> &e : physics_picking_events) {
Ref<InputEventMouse> m = e;
if (m.is_valid()) {
has_mouse_event = true;
break;
}
}
if (!has_mouse_event) {
// If no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
// While this extra event is sent, it is checked if both camera and last object and last ID did not move.
// If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame.
bool has_mouse_event = false;
for (const Ref<InputEvent> &m : physics_picking_events) {
if (m.is_valid()) {
has_mouse_event = true;
break;
}
}
Ref<InputEventMouseMotion> mm;
mm.instantiate();
if (!has_mouse_event) {
Ref<InputEventMouseMotion> mm;
mm.instantiate();
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_global_position(physics_last_mousepos);
mm->set_position(physics_last_mousepos);
mm->set_alt_pressed(physics_last_mouse_state.alt);
mm->set_shift_pressed(physics_last_mouse_state.shift);
mm->set_ctrl_pressed(physics_last_mouse_state.control);
mm->set_meta_pressed(physics_last_mouse_state.meta);
mm->set_button_mask(physics_last_mouse_state.mouse_mask);
physics_picking_events.push_back(mm);
}
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_position(get_mouse_position());
mm->set_global_position(mm->get_position());
mm->set_alt_pressed(Input::get_singleton()->is_key_pressed(Key::ALT));
mm->set_shift_pressed(Input::get_singleton()->is_key_pressed(Key::SHIFT));
mm->set_ctrl_pressed(Input::get_singleton()->is_key_pressed(Key::CTRL));
mm->set_meta_pressed(Input::get_singleton()->is_key_pressed(Key::META));
mm->set_button_mask(Input::get_singleton()->get_mouse_button_mask());
physics_picking_events.push_back(mm);
}
while (physics_picking_events.size()) {
@ -722,14 +721,6 @@ void Viewport::_process_picking() {
if (mm.is_valid()) {
pos = mm->get_position();
is_mouse = true;
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
physics_last_mouse_state.alt = mm->is_alt_pressed();
physics_last_mouse_state.shift = mm->is_shift_pressed();
physics_last_mouse_state.control = mm->is_ctrl_pressed();
physics_last_mouse_state.meta = mm->is_meta_pressed();
physics_last_mouse_state.mouse_mask = mm->get_button_mask();
}
Ref<InputEventMouseButton> mb = ev;
@ -737,34 +728,6 @@ void Viewport::_process_picking() {
if (mb.is_valid()) {
pos = mb->get_position();
is_mouse = true;
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
physics_last_mouse_state.alt = mb->is_alt_pressed();
physics_last_mouse_state.shift = mb->is_shift_pressed();
physics_last_mouse_state.control = mb->is_ctrl_pressed();
physics_last_mouse_state.meta = mb->is_meta_pressed();
if (mb->is_pressed()) {
physics_last_mouse_state.mouse_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
} else {
physics_last_mouse_state.mouse_mask.clear_flag(mouse_button_to_mask(mb->get_button_index()));
// If touch mouse raised, assume we don't know last mouse pos until new events come
if (mb->get_device() == InputEvent::DEVICE_ID_EMULATION) {
physics_has_last_mousepos = false;
}
}
}
Ref<InputEventKey> k = ev;
if (k.is_valid()) {
// Only for mask.
physics_last_mouse_state.alt = k->is_alt_pressed();
physics_last_mouse_state.shift = k->is_shift_pressed();
physics_last_mouse_state.control = k->is_ctrl_pressed();
physics_last_mouse_state.meta = k->is_meta_pressed();
continue;
}
Ref<InputEventScreenDrag> sd = ev;
@ -2509,8 +2472,6 @@ void Viewport::_drop_mouse_focus() {
}
void Viewport::_drop_physics_mouseover(bool p_paused_only) {
physics_has_last_mousepos = false;
_cleanup_mouseover_colliders(true, p_paused_only);
#ifndef _3D_DISABLED
@ -3077,13 +3038,11 @@ void Viewport::_push_unhandled_input_internal(const Ref<InputEvent> &p_event) {
if (physics_object_picking && !is_input_handled()) {
if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
(Object::cast_to<InputEventMouseButton>(*p_event) ||
Object::cast_to<InputEventMouseMotion>(*p_event) ||
(Object::cast_to<InputEventMouse>(*p_event) ||
Object::cast_to<InputEventScreenDrag>(*p_event) ||
Object::cast_to<InputEventScreenTouch>(*p_event) ||
Object::cast_to<InputEventKey>(*p_event) // To remember state.
Object::cast_to<InputEventScreenTouch>(*p_event)
)) {
)) {
physics_picking_events.push_back(p_event);
set_input_as_handled();
}

View File

@ -256,16 +256,6 @@ private:
Transform3D physics_last_object_transform;
Transform3D physics_last_camera_transform;
ObjectID physics_last_id;
bool physics_has_last_mousepos = false;
Vector2 physics_last_mousepos = Vector2(INFINITY, INFINITY);
struct {
bool alt = false;
bool control = false;
bool shift = false;
bool meta = false;
BitField<MouseButtonMask> mouse_mask;
} physics_last_mouse_state;
bool handle_input_locally = true;
bool local_input_handled = false;