feat: complete mobile UI implementation

This commit is contained in:
shenlei
2026-09-04 19:54:33 +09:00
parent 9a4a044da5
commit b19d5b5dd3
132 changed files with 6643 additions and 180 deletions
+53 -3
View File
@@ -57,6 +57,9 @@ var rotation_speed_deg := ROT_SPEED_DEFAULT_DEG # 上/下马时由 net_play 切
# (§3.2 __EnableSkipCollision,观战 / 服务器纠正时置真)。
var skip_actor_collision := false
var _last_wasd := Vector2.ZERO
var _mobile_axis := Vector2.ZERO
var _mobile_active := false
var _mobile_ui_touches := {}
# --- §3.1 Src/Dst 移动模型(对齐 InstanceBaseMovement.cpp NEW_Goto / NEW_MoveToDirection---
# _is_going = m_isGoing(点地走向 Dst);方向键移动 _is_going 保持 false。
@@ -100,6 +103,34 @@ func set_input_surfaces(cursor: Node, ui: Node = null, ground: Node = null,
cancel_fishing_input = cancel_fishing_cb
cancel_fishing_ground = ground_cancel_fishing_cb
# MobileUiRoot feeds a normalized left-thumb axis directly. Keeping it on the
# controller (instead of synthesizing keyboard events) preserves the existing
# camera-relative movement, collision and animation path for both platforms.
func set_mobile_axis(axis: Vector2) -> void:
_mobile_axis = axis.limit_length(1.0)
func clear_mobile_input() -> void:
_mobile_axis = Vector2.ZERO
_mobile_active = false
_mobile_ui_touches.clear()
if _touch_count == 0:
_multi_gesture = false
## MobileInputOverlay calls this before/after a control consumes its touch.
## World touch handling must know about that finger even though the GUI event
## never reaches _unhandled_input; otherwise a joystick finger plus a world
## finger can look like a single tap-to-move gesture.
func set_mobile_ui_touch(index: int, pressed: bool) -> void:
if pressed:
_mobile_ui_touches[index] = true
if _touch_count > 0:
_multi_gesture = true
_tap_index = -1
else:
_mobile_ui_touches.erase(index)
if _touch_count == 0 and _mobile_ui_touches.is_empty():
_multi_gesture = false
# 程序化下发一个点地目标(脚本化截图 / AI)——等价 NEW_MoveToDestPixelPositionDirection。
func walk_to(world_pos: Vector3) -> void:
_goto(Vector3(world_pos.x, 0.0, world_pos.z))
@@ -136,7 +167,7 @@ func _unhandled_input(e: InputEvent) -> void:
func _on_touch(e: InputEventScreenTouch) -> void:
if e.pressed:
_touch_count += 1
if _touch_count >= 2:
if _touch_count >= 2 or not _mobile_ui_touches.is_empty():
_multi_gesture = true
_tap_index = -1
elif not _multi_gesture:
@@ -151,7 +182,7 @@ func _on_touch(e: InputEventScreenTouch) -> void:
if travel <= _TAP_TRAVEL_MAX and held <= _TAP_TIME_MAX:
_on_click(e.position)
_tap_index = -1
if _touch_count == 0:
if _touch_count == 0 and _mobile_ui_touches.is_empty():
_multi_gesture = false
func _on_click(screen_pos: Vector2) -> void:
@@ -319,8 +350,25 @@ func _process(dt: float) -> void:
_run = force_run or Input.is_key_pressed(RUN_HOLD_KEY)
var wish := Vector3.ZERO
var wasd := _wasd()
var mobile_axis := _mobile_axis
if wasd != Vector2.ZERO:
if mobile_axis != Vector2.ZERO:
# A new thumb gesture has the same fishing-cancel edge as a keyboard move.
if not _mobile_active and cancel_fishing_input.is_valid() \
and bool(cancel_fishing_input.call()):
_mobile_active = true
_last_wasd = Vector2.ZERO
anim_state.emit("wait")
return
_mobile_active = true
_is_going = false
_last_wasd = Vector2.ZERO
var mobile_yaw: float = (camera.heading() if camera and camera.has_method("heading") else 0.0)
var mobile_fwd := Vector3(sin(mobile_yaw), 0, cos(mobile_yaw))
var mobile_right := Vector3(mobile_fwd.z, 0, -mobile_fwd.x)
wish = (mobile_fwd * -mobile_axis.y + mobile_right * mobile_axis.x).normalized()
elif wasd != Vector2.ZERO:
_mobile_active = false
# PythonPlayerInputKeyboard 只在方向键按下时尝试取消钓鱼;记录方向
# 边沿,避免按住键时每帧重复发送 CG_FISHING(0)。
if wasd != _last_wasd and cancel_fishing_input.is_valid() \
@@ -335,12 +383,14 @@ func _process(dt: float) -> void:
var right := Vector3(fwd.z, 0, -fwd.x)
wish = (fwd * -wasd.y + right * wasd.x).normalized()
elif _is_going:
_mobile_active = false
var flat := Vector3(_dst_pos.x - player.position.x, 0, _dst_pos.z - player.position.z)
if flat.length() <= ARRIVE_EPS:
_is_going = false
else:
wish = flat.normalized()
else:
_mobile_active = false
_last_wasd = Vector2.ZERO
var speed := 0.0