191 lines
7.5 KiB
GDScript
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")
|