feat: complete mobile UI implementation
This commit is contained in:
+217
-21
@@ -14,6 +14,7 @@
|
||||
# 辅助页 HIDE_SUPPORT_SKILL_POINT 整页隐藏。升级结果仍由 GC_SKILL_LEVEL 回包驱动。
|
||||
extends Node
|
||||
|
||||
const MobileTouchButton = preload("res://ui/mobile/mobile_touch_button.gd")
|
||||
const TABS := ["主动", "辅助", "坐骑"]
|
||||
const MASTER_SUFFIX := ["", " M", " G", " P"] # master_type 0..3
|
||||
|
||||
@@ -28,6 +29,11 @@ var ui: CanvasLayer # UiManager
|
||||
var job := "WARRIOR"
|
||||
var drag_skill_id := 0
|
||||
var _tab := 0
|
||||
var _mobile_mode := false
|
||||
var _mobile_quickbar: Node
|
||||
var _mobile_hint: Label
|
||||
var _mobile_drop_slots: Array[MobileTouchButton] = []
|
||||
var _mobile_drag_quickbar_slot := -1
|
||||
|
||||
var _win: Control
|
||||
var _rows := {} # skill_id -> {lv, up}
|
||||
@@ -44,6 +50,15 @@ func set_job(j: String) -> void:
|
||||
if is_open():
|
||||
_rebuild()
|
||||
|
||||
func set_mobile_mode(enabled: bool) -> void:
|
||||
_mobile_mode = enabled
|
||||
if _mobile_mode and _win:
|
||||
close()
|
||||
|
||||
func set_mobile_quickbar(quickbar: Node) -> void:
|
||||
_mobile_quickbar = quickbar
|
||||
_refresh_mobile_quickbar_targets()
|
||||
|
||||
func is_open() -> bool:
|
||||
return _win != null and is_instance_valid(_win)
|
||||
|
||||
@@ -56,6 +71,8 @@ func close() -> void:
|
||||
ui.close(_win)
|
||||
_win = null
|
||||
_rows.clear()
|
||||
_mobile_drop_slots.clear()
|
||||
_mobile_drag_quickbar_slot = -1
|
||||
|
||||
func _cat_key() -> String:
|
||||
match _tab:
|
||||
@@ -67,9 +84,16 @@ func open() -> void:
|
||||
if is_open() or table == null:
|
||||
return
|
||||
_win = Control.new()
|
||||
_win.set_anchors_preset(Control.PRESET_CENTER_RIGHT)
|
||||
_win.position = Vector2(-300, -240)
|
||||
_win.size = Vector2(290, 470)
|
||||
_win.name = "MobileSkillWindow" if _mobile_mode else "SkillWindow"
|
||||
if _mobile_mode:
|
||||
_win.set_anchors_preset(Control.PRESET_TOP_LEFT)
|
||||
_win.position = Vector2.ZERO
|
||||
_win.size = Vector2(760, 340)
|
||||
_win.set_meta("mobile_title", "技能")
|
||||
else:
|
||||
_win.set_anchors_preset(Control.PRESET_CENTER_RIGHT)
|
||||
_win.position = Vector2(-300, -240)
|
||||
_win.size = Vector2(290, 470)
|
||||
_win.set_meta("is_titlebar", true)
|
||||
var panel := Panel.new()
|
||||
panel.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
@@ -80,27 +104,54 @@ func open() -> void:
|
||||
_win.add_child(panel)
|
||||
var title := Label.new()
|
||||
title.text = "技能"
|
||||
title.position = Vector2(12, 8)
|
||||
title.position = Vector2(12, 8) if not _mobile_mode else Vector2(14, 48)
|
||||
title.visible = not _mobile_mode
|
||||
if _mobile_mode:
|
||||
title.add_theme_font_size_override("font_size", 15)
|
||||
_win.add_child(title)
|
||||
# 分类页签
|
||||
var tabrow := HBoxContainer.new()
|
||||
tabrow.name = "tabs"
|
||||
tabrow.position = Vector2(10, 30)
|
||||
tabrow.position = Vector2(10, 30) if not _mobile_mode else Vector2(14, 48)
|
||||
if _mobile_mode:
|
||||
tabrow.size = Vector2(360, 40)
|
||||
tabrow.add_theme_constant_override("separation", 6)
|
||||
_win.add_child(tabrow)
|
||||
for i in TABS.size():
|
||||
var b := Button.new()
|
||||
b.text = TABS[i]
|
||||
b.toggle_mode = true
|
||||
b.button_pressed = (i == _tab)
|
||||
if _mobile_mode:
|
||||
b.custom_minimum_size = Vector2(110, 38)
|
||||
b.add_theme_font_size_override("font_size", 12)
|
||||
var ti: int = i
|
||||
b.pressed.connect(func(): _switch_tab(ti))
|
||||
tabrow.add_child(b)
|
||||
var vb := VBoxContainer.new()
|
||||
vb.name = "list"
|
||||
vb.position = Vector2(10, 60)
|
||||
vb.custom_minimum_size = Vector2(270, 0)
|
||||
vb.position = Vector2(10, 60) if not _mobile_mode else Vector2(0, 0)
|
||||
vb.custom_minimum_size = Vector2(270, 0) if not _mobile_mode else Vector2(720, 0)
|
||||
vb.add_theme_constant_override("separation", 2)
|
||||
_win.add_child(vb)
|
||||
if _mobile_mode:
|
||||
var scroll := ScrollContainer.new()
|
||||
scroll.name = "SkillScroll"
|
||||
scroll.position = Vector2(14, 92)
|
||||
scroll.size = Vector2(732, 214)
|
||||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
scroll.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
scroll.add_child(vb)
|
||||
_win.add_child(scroll)
|
||||
_mobile_hint = Label.new()
|
||||
_mobile_hint.position = Vector2(14, 310)
|
||||
_mobile_hint.size = Vector2(720, 22)
|
||||
_mobile_hint.add_theme_font_size_override("font_size", 10)
|
||||
_mobile_hint.add_theme_color_override("font_color", Color(0.62, 0.72, 0.84))
|
||||
_mobile_hint.text = "可用点数与技能等级由服务器实时确认"
|
||||
_win.add_child(_mobile_hint)
|
||||
_build_mobile_quickbar_targets()
|
||||
else:
|
||||
_win.add_child(vb)
|
||||
ui.open(_win)
|
||||
_rebuild()
|
||||
|
||||
@@ -113,7 +164,11 @@ func _switch_tab(i: int) -> void:
|
||||
_rebuild()
|
||||
|
||||
func _rebuild() -> void:
|
||||
var vb: VBoxContainer = _win.get_node("list")
|
||||
var vb: VBoxContainer = _win.get_node_or_null("list") as VBoxContainer
|
||||
if vb == null and _mobile_mode:
|
||||
vb = _win.get_node_or_null("SkillScroll/list") as VBoxContainer
|
||||
if vb == null:
|
||||
return
|
||||
for c in vb.get_children():
|
||||
c.queue_free()
|
||||
_rows.clear()
|
||||
@@ -125,19 +180,39 @@ func _rebuild() -> void:
|
||||
return
|
||||
for id in ids:
|
||||
var row := HBoxContainer.new()
|
||||
row.custom_minimum_size = Vector2(268, 26)
|
||||
var nm := Label.new()
|
||||
nm.text = table.name_of(id)
|
||||
nm.custom_minimum_size = Vector2(140, 0)
|
||||
nm.add_theme_font_size_override("font_size", 12)
|
||||
row.custom_minimum_size = Vector2(720, 46) if _mobile_mode else Vector2(268, 26)
|
||||
var nm: Control
|
||||
if _mobile_mode:
|
||||
var skill_name := MobileTouchButton.new()
|
||||
skill_name.setup(table.name_of(id), Color(0.34, 0.58, 0.88, 0.88))
|
||||
skill_name.set_rect_style()
|
||||
skill_name.set_gesture_enabled(true)
|
||||
skill_name.custom_minimum_size = Vector2(300, 42)
|
||||
skill_name.size = Vector2(300, 42)
|
||||
var skill_button := skill_name
|
||||
skill_button.long_pressed.connect(func(): _mobile_begin_skill_drag(id, skill_button))
|
||||
skill_button.drag_changed.connect(func(_delta: Vector2):
|
||||
_mobile_update_skill_drag(id, skill_button))
|
||||
skill_button.drag_released.connect(func(_delta: Vector2):
|
||||
_mobile_end_skill_drag(id, skill_button))
|
||||
nm = skill_name
|
||||
else:
|
||||
var skill_label := Label.new()
|
||||
skill_label.text = table.name_of(id)
|
||||
skill_label.custom_minimum_size = Vector2(140, 0)
|
||||
skill_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
skill_label.add_theme_font_size_override("font_size", 12)
|
||||
nm = skill_label
|
||||
row.add_child(nm)
|
||||
var lv := Label.new()
|
||||
lv.name = "lv"
|
||||
lv.custom_minimum_size = Vector2(58, 0)
|
||||
lv.add_theme_font_size_override("font_size", 12)
|
||||
lv.custom_minimum_size = Vector2(100, 42) if _mobile_mode else Vector2(58, 0)
|
||||
lv.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
lv.add_theme_font_size_override("font_size", 13 if _mobile_mode else 12)
|
||||
row.add_child(lv)
|
||||
var tag := Label.new()
|
||||
tag.custom_minimum_size = Vector2(40, 0)
|
||||
tag.custom_minimum_size = Vector2(76, 42) if _mobile_mode else Vector2(40, 0)
|
||||
tag.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
tag.add_theme_font_size_override("font_size", 10)
|
||||
if table.is_passive(id):
|
||||
tag.text = "被动"
|
||||
@@ -150,17 +225,138 @@ func _rebuild() -> void:
|
||||
if table.can_level_up(id) and not table.is_passive(id):
|
||||
var up := Button.new()
|
||||
up.text = "+"
|
||||
up.custom_minimum_size = Vector2(28, 22)
|
||||
up.custom_minimum_size = Vector2(48, 42) if _mobile_mode else Vector2(28, 22)
|
||||
if _mobile_mode:
|
||||
up.add_theme_font_size_override("font_size", 18)
|
||||
up.pressed.connect(func(): client.skill_up(sid))
|
||||
row.add_child(up)
|
||||
_rows[id] = {"lv": lv, "up": up}
|
||||
else:
|
||||
_rows[id] = {"lv": lv, "up": null}
|
||||
nm.gui_input.connect(func(e: InputEvent):
|
||||
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT:
|
||||
drag_skill_id = sid)
|
||||
if not _mobile_mode:
|
||||
nm.gui_input.connect(func(e: InputEvent):
|
||||
if e is InputEventMouseButton and e.pressed and e.button_index == MOUSE_BUTTON_LEFT:
|
||||
drag_skill_id = sid
|
||||
if _mobile_hint: _mobile_hint.text = "已选择:%s;点击快捷栏按钮自动放入空位" % table.name_of(sid)
|
||||
nm.accept_event())
|
||||
if _mobile_mode:
|
||||
var assign := Button.new()
|
||||
assign.text = "快捷栏"
|
||||
assign.custom_minimum_size = Vector2(92, 42)
|
||||
assign.add_theme_font_size_override("font_size", 11)
|
||||
assign.pressed.connect(func(): _mobile_assign_skill(sid))
|
||||
row.add_child(assign)
|
||||
vb.add_child(row)
|
||||
refresh()
|
||||
_refresh_mobile_quickbar_targets()
|
||||
|
||||
func _build_mobile_quickbar_targets() -> void:
|
||||
var title := Label.new()
|
||||
title.text = "快捷栏"
|
||||
title.position = Vector2(390, 48)
|
||||
title.size = Vector2(60, 38)
|
||||
title.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
title.add_theme_font_size_override("font_size", 12)
|
||||
title.add_theme_color_override("font_color", Color(0.95, 0.82, 0.54))
|
||||
title.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_win.add_child(title)
|
||||
for i in 8:
|
||||
var target := MobileTouchButton.new()
|
||||
target.setup("—", Color(0.42, 0.65, 0.92, 0.9))
|
||||
target.set_rect_style()
|
||||
target.set_gesture_enabled(true)
|
||||
target.position = Vector2(448 + i * 38, 48)
|
||||
target.size = Vector2(34, 38)
|
||||
target.custom_minimum_size = Vector2(34, 38)
|
||||
var slot := i
|
||||
target.pressed.connect(func(): _mobile_drop_on_quickbar(slot))
|
||||
target.long_pressed.connect(func(): _mobile_begin_quickbar_drag(slot))
|
||||
target.drag_released.connect(func(_delta: Vector2): _mobile_end_quickbar_drag(slot, target))
|
||||
_win.add_child(target)
|
||||
_mobile_drop_slots.append(target)
|
||||
|
||||
func _mobile_begin_skill_drag(skill_id: int, _button: MobileTouchButton) -> void:
|
||||
drag_skill_id = skill_id
|
||||
if _mobile_hint:
|
||||
_mobile_hint.text = "拖到上方快捷栏槽位,松手放入"
|
||||
|
||||
func _mobile_update_skill_drag(skill_id: int, _button: MobileTouchButton) -> void:
|
||||
if drag_skill_id == skill_id and _mobile_hint:
|
||||
_mobile_hint.text = "拖到上方快捷栏槽位,松手放入"
|
||||
|
||||
func _mobile_end_skill_drag(skill_id: int, button: MobileTouchButton) -> void:
|
||||
if drag_skill_id != skill_id:
|
||||
return
|
||||
var target := _mobile_drop_slot_at(button.drag_end_position())
|
||||
if target >= 0 and _mobile_quickbar and _mobile_quickbar.has_method("assign"):
|
||||
if bool(_mobile_quickbar.assign(target, "skill", skill_id)):
|
||||
drag_skill_id = 0
|
||||
_refresh_mobile_quickbar_targets()
|
||||
if _mobile_hint: _mobile_hint.text = "已放入快捷栏第 %d 格" % (target + 1)
|
||||
return
|
||||
if _mobile_hint:
|
||||
_mobile_hint.text = "已选择:%s;可拖到快捷栏" % table.name_of(skill_id)
|
||||
|
||||
func _mobile_drop_on_quickbar(slot: int) -> void:
|
||||
if _mobile_quickbar == null or not _mobile_quickbar.has_method("assign"):
|
||||
return
|
||||
if drag_skill_id != 0:
|
||||
if bool(_mobile_quickbar.assign(slot, "skill", drag_skill_id)):
|
||||
drag_skill_id = 0
|
||||
_refresh_mobile_quickbar_targets()
|
||||
if _mobile_hint: _mobile_hint.text = "已放入快捷栏第 %d 格" % (slot + 1)
|
||||
|
||||
func _mobile_begin_quickbar_drag(slot: int) -> void:
|
||||
_mobile_drag_quickbar_slot = slot
|
||||
if _mobile_hint:
|
||||
_mobile_hint.text = "拖到另一个快捷栏槽位以交换"
|
||||
|
||||
func _mobile_end_quickbar_drag(slot: int, button: MobileTouchButton) -> void:
|
||||
if _mobile_drag_quickbar_slot != slot:
|
||||
return
|
||||
var target := _mobile_drop_slot_at(button.drag_end_position())
|
||||
if target >= 0 and target != slot and _mobile_quickbar \
|
||||
and _mobile_quickbar.has_method("mobile_swap"):
|
||||
_mobile_quickbar.mobile_swap(slot, target)
|
||||
_refresh_mobile_quickbar_targets()
|
||||
if _mobile_hint: _mobile_hint.text = "已交换快捷栏位置"
|
||||
_mobile_drag_quickbar_slot = -1
|
||||
|
||||
func _mobile_drop_slot_at(position: Vector2) -> int:
|
||||
for i in _mobile_drop_slots.size():
|
||||
var slot := _mobile_drop_slots[i]
|
||||
if slot and slot.get_global_rect().has_point(position):
|
||||
return i
|
||||
return -1
|
||||
|
||||
func _refresh_mobile_quickbar_targets() -> void:
|
||||
if not _mobile_mode:
|
||||
return
|
||||
for i in _mobile_drop_slots.size():
|
||||
var slot := _mobile_drop_slots[i]
|
||||
if slot == null or _mobile_quickbar == null:
|
||||
continue
|
||||
var state: Dictionary = _mobile_quickbar.mobile_slot_state(i) \
|
||||
if _mobile_quickbar.has_method("mobile_slot_state") else {}
|
||||
var label := "—"
|
||||
if state.get("kind", "") == "skill" and table:
|
||||
label = table.name_of(int(state.get("id", 0))).substr(0, 4)
|
||||
elif state.get("kind", "") == "item":
|
||||
label = "物"
|
||||
elif state.get("kind", "") == "emote":
|
||||
label = "表"
|
||||
slot.set_caption(label)
|
||||
|
||||
func _mobile_assign_skill(skill_id: int) -> void:
|
||||
if _mobile_quickbar == null or not _mobile_quickbar.has_method("assign_mobile"):
|
||||
if _mobile_hint: _mobile_hint.text = "快捷栏暂不可用"
|
||||
return
|
||||
if bool(_mobile_quickbar.assign_mobile("skill", skill_id)):
|
||||
drag_skill_id = 0
|
||||
_refresh_mobile_quickbar_targets()
|
||||
if _mobile_hint: _mobile_hint.text = "已放入快捷栏"
|
||||
else:
|
||||
if _mobile_hint: _mobile_hint.text = "快捷栏已满,请先移除一个技能"
|
||||
|
||||
func refresh() -> void:
|
||||
if not is_open():
|
||||
|
||||
Reference in New Issue
Block a user