Stabilize camera input across fishing and radial menus

This commit is contained in:
Alexander Sellite 2026-08-22 22:56:30 -04:00
parent 6fd1aa0388
commit 8f8398cbcd
4 changed files with 147 additions and 43 deletions

View file

@ -312,10 +312,23 @@ func _run() -> void:
Input.parse_input_event(right_stick_motion)
await process_frame
# Chat owns all movement while text entry is active, including developer
# freecam movement which reads the same WASD actions as the player.
var free_camera_body := player.get("_free_camera_body") as CharacterBody3D
assert(free_camera_body != null)
# A released fishing cast locks only the avatar. The detached camera must
# continue to accept translation while that movement lock is active.
player.set_movement_enabled(false)
var cast_locked_camera_position: Vector3 = free_camera_body.global_position
Input.action_press("move_forward")
for _frame: int in 3:
await physics_frame
Input.action_release("move_forward")
assert(not free_camera_body.global_position.is_equal_approx(
cast_locked_camera_position
))
player.set_movement_enabled(true)
# Chat owns all movement while text entry is active, including developer
# freecam movement which reads the same WASD actions as the player.
chat_ui.open_chat()
assert(chat_ui.is_open())
var free_camera_position_before: Vector3 = free_camera_body.global_position

View file

@ -30,8 +30,14 @@ func _run() -> void:
var player := main.get("_player") as Player
var fishing_spot := main.get_node("%FishingSpot") as FishingSpot
var game_ui := main.get_node("%GameUI") as GameUI
var catalog := main.get("fish_catalog") as FishPool
assert(player != null and fishing_spot != null and catalog != null)
assert(
player != null
and fishing_spot != null
and game_ui != null
and catalog != null
)
fishing_spot.minimum_showcase_duration = 0.15
assert(player.bag.add_item(&"crab_net"))
assert(player.hotbar.assign_item(0, &"crab_net"))
@ -82,6 +88,18 @@ func _run() -> void:
await process_frame
assert(fishing_spot.get("_pending_catch") == null)
# A radial menu can open after the showcase panel disappears but before the
# pocket animation restores gameplay. Its camera lock must not overwrite the
# showcase's underlying camera state when the two finish in either order.
Input.action_press("open_emotes")
var emote_press := InputEventAction.new()
emote_press.action = &"open_emotes"
emote_press.pressed = true
game_ui.call("_input", emote_press)
var emote_menu := game_ui.get_node("%EmoteRadialMenu") as EmoteRadialMenu
assert(emote_menu.is_open())
assert(not bool(player.call("_is_camera_input_enabled")))
var pocket_deadline: int = Time.get_ticks_msec() + 6000
while (
Time.get_ticks_msec() < pocket_deadline
@ -91,6 +109,23 @@ func _run() -> void:
assert(fishing_spot.state == FishingSpot.FishingState.READY)
assert(player.is_movement_enabled())
assert(bool(player.call("_is_movement_input_enabled")))
assert(not bool(player.call("_is_camera_input_enabled")))
Input.action_release("open_emotes")
var emote_release := InputEventAction.new()
emote_release.action = &"open_emotes"
emote_release.pressed = false
game_ui.call("_input", emote_release)
assert(not emote_menu.is_open())
assert(bool(player.call("_is_camera_input_enabled")))
# A focused chat field or popup can consume the wheel's release event. The
# polled action state must still close the radial and release its camera lock.
Input.action_press("open_emotes")
game_ui.call("_input", emote_press)
assert(emote_menu.is_open())
Input.action_release("open_emotes")
await process_frame
assert(not emote_menu.is_open())
assert(bool(player.call("_is_camera_input_enabled")))
assert(player.inventory.contains_catch_id(crab_catch.catch_id))
assert(bool(player.get("_active_item_is_net")))