Files
mtgodot-poc/project/mobile_ui_test.gd
T

117 lines
4.5 KiB
GDScript

# mobile_ui_test —— mobile presentation smoke test without a server or assets.
# godot --headless --path project --script mobile_ui_test.gd
extends SceneTree
const UiProfile := preload("res://ui/ui_profile.gd")
const MobileHud := preload("res://ui/mobile/mobile_hud.gd")
const MobileUiRoot := preload("res://ui/mobile/mobile_ui_root.gd")
const MobileMenuDrawer := preload("res://ui/mobile/mobile_menu_drawer.gd")
const MobileWindowHost := preload("res://ui/mobile/mobile_window_host.gd")
const PlayerCtl := preload("res://player_controller.gd")
class FakeClient extends Node:
signal party_changed
signal vitals_changed(vid: int)
var main := 7
var entity := {"vid": 7, "name": "测试角色", "race": 0, "level": 12}
var party := [{"vid": 7, "name": "测试角色", "hp_pct": 100, "leader": true}]
func get_main_vid() -> int: return main
func get_entity(_vid: int) -> Dictionary: return entity
func get_party() -> Array: return party
func set_target(_vid: int) -> bool: return true
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_ui_test (profile / landscape HUD / menu / controls)")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _run() -> void:
await process_frame
_ck(UiProfile.parse("mobile") == UiProfile.Mode.MOBILE, "profile parses mobile")
_ck(UiProfile.parse("desktop") == UiProfile.Mode.DESKTOP, "profile parses desktop")
_ck(UiProfile.parse("auto") == UiProfile.Mode.AUTO, "profile parses auto")
_ck(MobileUiRoot.requires_landscape(Vector2(844, 390)) == false,
"landscape design size is accepted")
_ck(MobileUiRoot.requires_landscape(Vector2(390, 844)),
"portrait viewport is rejected")
var safe := MobileWindowHost.safe_rect_for(Vector2(844, 390),
Rect2(20, 8, 804, 374))
_ck(safe == Rect2(20, 8, 804, 374), "reported safe area is preserved")
_ck(MobileWindowHost.safe_rect_for(Vector2(844, 390),
Rect2(0, 0, 1920, 1080)) == Rect2(0, 0, 844, 390),
"physical-screen safe area is rejected for a logical viewport")
var client := FakeClient.new()
get_root().add_child(client)
var root := MobileUiRoot.new()
get_root().add_child(root)
root.setup(null, null, client)
root.bind_controls({"client": client})
await process_frame
_ck(root.hud_view is MobileHud, "mobile root owns mobile HUD")
_ck(root.input_overlay != null, "mobile root owns touch overlay")
_ck(root.hud_view._player_name.text == "测试角色", "avatar card uses server player name")
root.set_vitals(50, 100, 20, 40)
_ck(root.hud_view._hp_bar.value == 50 and root.hud_view._mp_bar.value == 20,
"mobile HUD updates HP/SP through compatibility setters")
root.set_target("目标", 35)
_ck(root.hud_view._target_panel.visible and root.hud_view._target_bar.value == 35,
"mobile HUD shows target status")
root.menu_drawer.open()
_ck(root.menu_drawer.is_open(), "mobile menu opens")
_ck(MobileMenuDrawer.CATEGORIES.size() == 5, "mobile menu has five top-level categories")
_ck(not MobileMenuDrawer.ITEMS["社交"].has("队伍"), "social menu has no party entry")
root.menu_drawer.close()
var pc := PlayerCtl.new()
get_root().add_child(pc)
pc.player = Node3D.new()
get_root().add_child(pc.player)
root.input_overlay.bind_controls(pc, null, null, null)
await process_frame
var touch_pos: Vector2 = root.input_overlay._joystick.get_global_rect().get_center()
var ui_down := InputEventScreenTouch.new()
ui_down.index = 21
ui_down.pressed = true
ui_down.position = touch_pos
root.input_overlay._input(ui_down)
_ck(pc._mobile_ui_touches.has(21), "UI touch is registered by world-touch arbiter")
var world_down := InputEventScreenTouch.new()
world_down.index = 22
world_down.pressed = true
world_down.position = Vector2(600, 210)
pc._on_touch(world_down)
var world_up := InputEventScreenTouch.new()
world_up.index = 22
world_up.pressed = false
world_up.position = world_down.position
pc._on_touch(world_up)
_ck(pc._multi_gesture, "joystick plus world touch cannot become tap-to-move")
var ui_up := InputEventScreenTouch.new()
ui_up.index = 21
ui_up.pressed = false
ui_up.position = touch_pos
root.input_overlay._input(ui_up)
_ck(not pc._mobile_ui_touches.has(21), "UI touch arbiter clears on release")
pc.set_mobile_axis(Vector2(2, 0))
_ck(pc._mobile_axis == Vector2(1, 0), "mobile movement axis is normalized")
pc.clear_mobile_input()
_ck(pc._mobile_axis == Vector2.ZERO, "mobile movement axis clears on cancellation")
root.queue_free()
pc.queue_free()
client.queue_free()