Files
mtgodot-poc/project/mobile_gesture_test.gd

191 lines
7.5 KiB
GDScript

# mobile_gesture_test —— 移动端长按、瞄准、快捷栏交换和物品触摸拖放。
# godot --display-driver headless --audio-driver Dummy --rendering-method gl_compatibility --path project --script mobile_gesture_test.gd
extends SceneTree
const TouchButton = preload("res://ui/mobile/mobile_touch_button.gd")
const Quickbar = preload("res://ui/quickbar.gd")
const SkillTable = preload("res://ui/skill_table.gd")
const SkillUI = preload("res://ui/skill_ui.gd")
const UiManager = preload("res://ui/ui_manager.gd")
const InventoryUI = preload("res://ui/inventory_ui.gd")
const MouseController = preload("res://ui/mouse_controller.gd")
class FakeClient extends Node:
var inventory := [{"cell": 5, "vnum": 19, "count": 2}]
var skills := [{"id": 1, "level": 5, "master": 0}, {"id": 16, "level": 3, "master": 0}]
var quickslots := []
var calls := []
var casts := []
var main := 1000
func get_main_vid() -> int: return main
func get_entity(_vid: int) -> Dictionary: return {"vid": _vid, "kind": 2, "race": 0}
func get_target() -> Dictionary: return {"vid": 2000}
func get_inventory() -> Array: return inventory
func get_equipment() -> Array: return []
func get_skills() -> Array: return skills
func get_skill_group() -> int: return 1
func get_points() -> Dictionary: return {"level": 30, "skill_active": 5, "skill_support": 3, "skill_horse": 2}
func get_quickslots() -> Array: return quickslots
func use_skill(id: int, target: int) -> bool:
calls.append(["use_skill", id, target]); return true
func cast_skill(motion: int, heading: float, x: int, y: int) -> bool:
casts.append([motion, heading, x, y]); return true
func quickslot_add(pos: int, kind: int, ref: int) -> bool:
calls.append(["quickslot_add", pos, kind, ref]); return true
func quickslot_swap(a: int, b: int) -> bool:
calls.append(["quickslot_swap", a, b]); return true
func use_item(window: int, cell: int) -> bool:
calls.append(["use_item", window, cell]); return true
func move_item(fw: int, fc: int, tw: int, tc: int, count: int) -> bool:
calls.append(["move_item", fw, fc, tw, tc, count]); return true
class FakeProto extends Node:
func item(vnum: int) -> Dictionary:
return {"vnum": vnum, "name": "Item%d" % vnum, "locale_name": "物品%d" % vnum,
"type": 1, "sub_type": 0, "anti_flags": 0, "wear_flags": 1 << 4,
"limits": []}
var _fail := 0
func _ck(condition: bool, message: String) -> void:
if not condition:
_fail += 1
printerr("FAIL: " + message)
func _init() -> void:
await _run()
if _fail == 0:
print("PASS: mobile_gesture_test (long press + aim + quickbar swap + item touch drag)")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _run() -> void:
await process_frame
# 1) 长按按钮必须保留同一 touch index,并在拖动松手时发出完成信号。
var gesture_host := Control.new()
get_root().add_child(gesture_host)
var gesture := TouchButton.new()
gesture.setup("技能", Color(0.4, 0.7, 1.0))
gesture.set_gesture_enabled(true)
gesture.size = Vector2(72, 72)
gesture_host.add_child(gesture)
var press_count := [0]
var long_count := [0]
var release_count := [0]
gesture.pressed.connect(func(): press_count[0] += 1)
gesture.long_pressed.connect(func(): long_count[0] += 1)
gesture.drag_released.connect(func(_delta: Vector2): release_count[0] += 1)
var down := InputEventScreenTouch.new()
down.index = 41
down.pressed = true
down.position = Vector2(30, 30)
gesture._gui_input(down)
await create_timer(0.65).timeout
var drag := InputEventScreenDrag.new()
drag.index = 41
drag.position = Vector2(52, 12)
gesture._gui_input(drag)
var up := InputEventScreenTouch.new()
up.index = 41
up.pressed = false
up.position = drag.position
gesture._gui_input(up)
_ck(press_count[0] == 1, "长按手势只触发一次按下")
_ck(long_count[0] == 1, "超过阈值后触发 long_pressed")
_ck(release_count[0] == 1 and not gesture.active, "拖动松手发出 drag_released 并清理状态")
# 2) 快捷栏保持服务器槽位交换,同时瞄准方向进入 cast_skill heading。
var assets := AssetRoot.path()
var table := SkillTable.new()
var loaded := false
for lang in ["en", "common"]:
if table.load_file(assets.path_join("locale/locale/%s/skilldesc.txt" % lang)):
loaded = true
break
if not loaded:
print(" (skip: no skilldesc.txt)")
return
var ui: CanvasLayer = UiManager.new()
get_root().add_child(ui)
ui._ready()
ui.set_mobile_mode(true)
var client := FakeClient.new()
get_root().add_child(client)
var player := Node3D.new()
get_root().add_child(player)
var quickbar: Node = Quickbar.new()
get_root().add_child(quickbar)
quickbar.setup(client, table, ui, func() -> Node: return player)
var skill_ui: Node = SkillUI.new()
get_root().add_child(skill_ui)
skill_ui.setup(client, table, ui)
skill_ui.set_mobile_mode(true)
skill_ui.set_mobile_quickbar(quickbar)
skill_ui.open()
await process_frame
_ck(skill_ui._mobile_drop_slots.size() == 8, "技能页创建 8 个移动快捷栏落点")
# 用真实技能行按钮的拖放结束坐标,验证技能可放入指定槽位。
var source: TouchButton = null
for row in skill_ui._win.get_node("SkillScroll/list").get_children():
if row.get_child_count() > 0 and row.get_child(0) is TouchButton:
source = row.get_child(0)
break
if source:
var target_pos: Vector2 = skill_ui._mobile_drop_slots[2].get_global_rect().get_center()
source._last_position = target_pos
skill_ui._mobile_begin_skill_drag(1, source)
skill_ui._mobile_end_skill_drag(1, source)
_ck(quickbar.mobile_slot_state(2).get("id", 0) == 1,
"长按技能拖放到第 3 格快捷栏")
quickbar.assign(0, "skill", 16)
quickbar.mobile_swap(0, 2)
_ck(quickbar.mobile_slot_state(0).get("id", 0) == 1
and quickbar.mobile_slot_state(2).get("id", 0) == 16,
"移动快捷栏交换更新本地槽位")
_ck(client.calls.has(["quickslot_swap", 0, 2]),
"移动快捷栏交换沿用 CG_QUICKSLOT_SWAP")
quickbar.activate_aimed(0, Vector2(1, 0))
_ck(client.casts.size() == 1 and client.calls.has(["use_skill", 1, 2000]),
"技能长按瞄准仍走 use_skill + cast_skill")
# 3) 背包长按详情后继续拖动,松手由 MouseController 落到目标格。
var proto := FakeProto.new()
get_root().add_child(proto)
var mouse: Node = MouseController.new()
get_root().add_child(mouse)
mouse.setup(ui)
var inventory: Node = InventoryUI.new()
inventory.item_mouse = mouse
get_root().add_child(inventory)
inventory.setup(ui, client, proto, assets)
inventory.set_mobile_mode(true)
inventory.open()
await process_frame
var source_cell: Panel = inventory._cells.get(5)
var target_cell: Panel = inventory._cells.get(8)
if source_cell and target_cell:
var item_down := InputEventScreenTouch.new()
item_down.index = 52
item_down.pressed = true
item_down.position = source_cell.get_global_rect().get_center()
inventory._on_cell_input(5, item_down)
await create_timer(0.65).timeout
_ck(inventory._mobile_detail_dialog != null, "物品长按先打开详情卡")
var item_drag := InputEventScreenDrag.new()
item_drag.index = 52
item_drag.position = target_cell.get_global_rect().get_center()
inventory._handle_mobile_cell_drag(5, item_drag)
_ck(mouse.is_attached(), "继续拖动后进入全局物品拖放状态")
var item_up := InputEventScreenTouch.new()
item_up.index = 52
item_up.pressed = false
item_up.position = item_drag.position
inventory._input(item_up)
mouse._input(item_up)
_ck(client.calls.has(["move_item", 1, 5, 1, 8, 2]),
"物品触摸松手落到目标格并保留堆叠数量")
else:
_ck(false, "inventory source/target cells exist")