Stabilize camera drag and Tab menu input
This commit is contained in:
parent
86e5980019
commit
bb1942a057
4 changed files with 43 additions and 38 deletions
|
|
@ -466,11 +466,10 @@ var _catch_attachment_offset: Vector3 = Vector3(0.0, 0.08, 0.04)
|
||||||
|
|
||||||
var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
||||||
var _camera_dragging: bool = false
|
var _camera_dragging: bool = false
|
||||||
var _camera_drag_button_held: bool = false
|
|
||||||
var _camera_input_enabled: bool = true
|
var _camera_input_enabled: bool = true
|
||||||
var _camera_drag_prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE
|
var _camera_drag_prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE
|
||||||
var _camera_drag_capture_pending: bool = false
|
var _camera_drag_pointer_origin: Vector2 = Vector2.ZERO
|
||||||
var _camera_drag_generation: int = 0
|
var _camera_drag_restore_pointer: bool = false
|
||||||
var _free_camera_active: bool = false
|
var _free_camera_active: bool = false
|
||||||
var _free_camera_body: CharacterBody3D
|
var _free_camera_body: CharacterBody3D
|
||||||
var _free_camera: Camera3D
|
var _free_camera: Camera3D
|
||||||
|
|
@ -1616,7 +1615,6 @@ func _input(event: InputEvent) -> void:
|
||||||
return
|
return
|
||||||
var mouse_button := event as InputEventMouseButton
|
var mouse_button := event as InputEventMouseButton
|
||||||
if mouse_button != null and event.is_action("camera_drag"):
|
if mouse_button != null and event.is_action("camera_drag"):
|
||||||
_camera_drag_button_held = mouse_button.pressed
|
|
||||||
_set_camera_dragging(mouse_button.pressed)
|
_set_camera_dragging(mouse_button.pressed)
|
||||||
return
|
return
|
||||||
var mouse_motion := event as InputEventMouseMotion
|
var mouse_motion := event as InputEventMouseMotion
|
||||||
|
|
@ -1626,7 +1624,6 @@ func _input(event: InputEvent) -> void:
|
||||||
_rotate_free_camera(mouse_motion.screen_relative * mouse_sensitivity)
|
_rotate_free_camera(mouse_motion.screen_relative * mouse_sensitivity)
|
||||||
else:
|
else:
|
||||||
_rotate_camera(mouse_motion.screen_relative * mouse_sensitivity)
|
_rotate_camera(mouse_motion.screen_relative * mouse_sensitivity)
|
||||||
_request_camera_drag_capture()
|
|
||||||
|
|
||||||
|
|
||||||
func _notification(what: int) -> void:
|
func _notification(what: int) -> void:
|
||||||
|
|
@ -1689,38 +1686,24 @@ func _set_camera_dragging(active: bool) -> void:
|
||||||
if _camera_dragging == active:
|
if _camera_dragging == active:
|
||||||
return
|
return
|
||||||
_camera_dragging = active
|
_camera_dragging = active
|
||||||
_camera_drag_generation += 1
|
|
||||||
_camera_drag_capture_pending = false
|
|
||||||
if active:
|
if active:
|
||||||
_camera_drag_prior_mouse_mode = Input.mouse_mode
|
_camera_drag_prior_mouse_mode = Input.mouse_mode
|
||||||
|
_camera_drag_restore_pointer = _camera_drag_prior_mouse_mode in [
|
||||||
|
Input.MOUSE_MODE_VISIBLE,
|
||||||
|
Input.MOUSE_MODE_CONFINED,
|
||||||
|
]
|
||||||
|
if _camera_drag_restore_pointer:
|
||||||
|
_camera_drag_pointer_origin = get_viewport().get_mouse_position()
|
||||||
|
# Capture starts with the physical press, before any motion is applied.
|
||||||
|
# Switching modes after the first movement can synthesize a center warp
|
||||||
|
# in the middle of the drag and interrupt camera control.
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
else:
|
else:
|
||||||
_camera_drag_button_held = false
|
|
||||||
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||||
Input.mouse_mode = _camera_drag_prior_mouse_mode
|
Input.mouse_mode = _camera_drag_prior_mouse_mode
|
||||||
|
if _camera_drag_restore_pointer:
|
||||||
|
Input.warp_mouse(_camera_drag_pointer_origin)
|
||||||
func _request_camera_drag_capture() -> void:
|
_camera_drag_restore_pointer = false
|
||||||
if (
|
|
||||||
_camera_drag_capture_pending
|
|
||||||
or Input.mouse_mode == Input.MOUSE_MODE_CAPTURED
|
|
||||||
):
|
|
||||||
return
|
|
||||||
_camera_drag_capture_pending = true
|
|
||||||
_capture_camera_drag_pointer.call_deferred(_camera_drag_generation)
|
|
||||||
|
|
||||||
|
|
||||||
func _capture_camera_drag_pointer(generation: int) -> void:
|
|
||||||
if generation != _camera_drag_generation:
|
|
||||||
return
|
|
||||||
_camera_drag_capture_pending = false
|
|
||||||
if (
|
|
||||||
not _camera_dragging
|
|
||||||
or not local_control_enabled
|
|
||||||
or not _is_camera_input_enabled()
|
|
||||||
or not _camera_drag_button_held
|
|
||||||
):
|
|
||||||
return
|
|
||||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
||||||
|
|
||||||
|
|
||||||
func _get_network_aware_speed() -> float:
|
func _get_network_aware_speed() -> float:
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,11 @@ func _run() -> void:
|
||||||
press.button_index = MOUSE_BUTTON_RIGHT
|
press.button_index = MOUSE_BUTTON_RIGHT
|
||||||
press.button_mask = MOUSE_BUTTON_MASK_RIGHT
|
press.button_mask = MOUSE_BUTTON_MASK_RIGHT
|
||||||
press.pressed = true
|
press.pressed = true
|
||||||
player.call("_input", press)
|
Input.parse_input_event(press)
|
||||||
|
await process_frame
|
||||||
assert(bool(player.get("_camera_dragging")))
|
assert(bool(player.get("_camera_dragging")))
|
||||||
if DisplayServer.get_name() != "headless":
|
if DisplayServer.get_name() != "headless":
|
||||||
assert(Input.mouse_mode == Input.MOUSE_MODE_VISIBLE)
|
assert(Input.mouse_mode == Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
var yaw := player.get_node("%CameraYaw") as Node3D
|
var yaw := player.get_node("%CameraYaw") as Node3D
|
||||||
var previous_yaw: float = yaw.rotation.y
|
var previous_yaw: float = yaw.rotation.y
|
||||||
|
|
@ -31,9 +32,9 @@ func _run() -> void:
|
||||||
motion.button_mask = MOUSE_BUTTON_MASK_RIGHT
|
motion.button_mask = MOUSE_BUTTON_MASK_RIGHT
|
||||||
motion.relative = Vector2(18.0, -4.0)
|
motion.relative = Vector2(18.0, -4.0)
|
||||||
motion.screen_relative = motion.relative
|
motion.screen_relative = motion.relative
|
||||||
player.call("_input", motion)
|
Input.parse_input_event(motion)
|
||||||
assert(not is_equal_approx(yaw.rotation.y, previous_yaw))
|
|
||||||
await process_frame
|
await process_frame
|
||||||
|
assert(not is_equal_approx(yaw.rotation.y, previous_yaw))
|
||||||
assert(bool(player.get("_camera_dragging")))
|
assert(bool(player.get("_camera_dragging")))
|
||||||
if DisplayServer.get_name() != "headless":
|
if DisplayServer.get_name() != "headless":
|
||||||
assert(Input.mouse_mode == Input.MOUSE_MODE_CAPTURED)
|
assert(Input.mouse_mode == Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
@ -41,12 +42,14 @@ func _run() -> void:
|
||||||
var release := InputEventMouseButton.new()
|
var release := InputEventMouseButton.new()
|
||||||
release.button_index = MOUSE_BUTTON_RIGHT
|
release.button_index = MOUSE_BUTTON_RIGHT
|
||||||
release.pressed = false
|
release.pressed = false
|
||||||
player.call("_input", release)
|
Input.parse_input_event(release)
|
||||||
|
await process_frame
|
||||||
assert(not bool(player.get("_camera_dragging")))
|
assert(not bool(player.get("_camera_dragging")))
|
||||||
if DisplayServer.get_name() != "headless":
|
if DisplayServer.get_name() != "headless":
|
||||||
assert(Input.mouse_mode == Input.MOUSE_MODE_VISIBLE)
|
assert(Input.mouse_mode == Input.MOUSE_MODE_VISIBLE)
|
||||||
|
|
||||||
player.call("_input", press)
|
Input.parse_input_event(press)
|
||||||
|
await process_frame
|
||||||
assert(bool(player.get("_camera_dragging")))
|
assert(bool(player.get("_camera_dragging")))
|
||||||
player.notification(NOTIFICATION_APPLICATION_FOCUS_OUT)
|
player.notification(NOTIFICATION_APPLICATION_FOCUS_OUT)
|
||||||
assert(not bool(player.get("_camera_dragging")))
|
assert(not bool(player.get("_camera_dragging")))
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,19 @@ func _run() -> void:
|
||||||
presentation.get("_neutral_focus_seed") == standard_button,
|
presentation.get("_neutral_focus_seed") == standard_button,
|
||||||
"the neutral menu focus seed did not remember the first action",
|
"the neutral menu focus seed did not remember the first action",
|
||||||
)
|
)
|
||||||
|
var player_menu_tab := InputEventKey.new()
|
||||||
|
player_menu_tab.physical_keycode = KEY_TAB
|
||||||
|
player_menu_tab.pressed = true
|
||||||
|
presentation._input(player_menu_tab)
|
||||||
|
await process_frame
|
||||||
|
_expect(
|
||||||
|
root.gui_get_focus_owner() == null,
|
||||||
|
"the default player-menu Tab was consumed as focus navigation",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
presentation.get("_neutral_focus_seed") == standard_button,
|
||||||
|
"the default player-menu Tab discarded the neutral focus seed",
|
||||||
|
)
|
||||||
var first_navigation := InputEventJoypadButton.new()
|
var first_navigation := InputEventJoypadButton.new()
|
||||||
first_navigation.button_index = JOY_BUTTON_DPAD_DOWN
|
first_navigation.button_index = JOY_BUTTON_DPAD_DOWN
|
||||||
first_navigation.pressed = true
|
first_navigation.pressed = true
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,12 @@ func _clear_directional_input_in_flight(generation: int) -> void:
|
||||||
func _is_directional_navigation(event: InputEvent) -> bool:
|
func _is_directional_navigation(event: InputEvent) -> bool:
|
||||||
if event is InputEventKey and (event as InputEventKey).echo:
|
if event is InputEventKey and (event as InputEventKey).echo:
|
||||||
return false
|
return false
|
||||||
|
# Tab is both Godot's default ui_focus_next key and NETfishing's default
|
||||||
|
# player-menu binding. The global focus presenter must leave that gameplay
|
||||||
|
# action alone; otherwise a remembered neutral focus seed consumes the key
|
||||||
|
# before PlayerMenu can open or close.
|
||||||
|
if event is InputEventKey and event.is_action_pressed(&"open_backpack"):
|
||||||
|
return false
|
||||||
return (
|
return (
|
||||||
event.is_action_pressed(&"ui_left")
|
event.is_action_pressed(&"ui_left")
|
||||||
or event.is_action_pressed(&"ui_right")
|
or event.is_action_pressed(&"ui_right")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue