# target_ui.gd —— 40250 目标信息板(TargetBoard)1:1 实现 # 严格对照: # root/uitarget.py:14-340 (TargetBoard) # UserInterface/InstanceBase.cpp (CanViewTargetHP) # root/localeinfo.py (TARGET_LEVEL_PAWN..KING) extends Node const UiAssets = preload("res://ui/ui_assets.gd") const GRADE_NAMES := { 0: "1阶", # nonplayer.PAWN: TARGET_LEVEL_PAWN 1: "2阶", # nonplayer.S_PAWN: TARGET_LEVEL_S_PAWN 2: "3阶", # nonplayer.KNIGHT: TARGET_LEVEL_KNIGHT 3: "4阶", # nonplayer.S_KNIGHT: TARGET_LEVEL_S_KNIGHT 4: "5阶首领", # nonplayer.BOSS: TARGET_LEVEL_BOSS 5: "6阶王", # nonplayer.KING: TARGET_LEVEL_KING } const DEFAULT_BOARD_WIDTH := 250.0 const BOARD_HEIGHT := 40.0 const GAUGE_WIDTH := 130.0 signal whisper_requested(name: String) signal exchange_requested(vid: int) signal fight_requested(vid: int) signal view_equipment_requested(vid: int) var client: Node var _root: Control var _board: Panel var _name_label: Label var _hp_gauge_bg: ColorRect var _hp_gauge_fill: ColorRect var _hp_text: Label var _close_button: Button var _button_container: HBoxContainer var _action_buttons: Dictionary = {} var _current_vid := 0 var _current_name := "" var _current_hp_pct := 100 var _is_pc := false var _shown := false var _assets_root := "" func setup(m2client: Node, parent: Node, assets := "") -> void: client = m2client _assets_root = assets _build(parent) func is_open() -> bool: return _shown and _root != null and _root.visible func get_target_vid() -> int: return _current_vid func get_target_name() -> String: return _current_name func get_hp_percentage() -> int: return _current_hp_pct func open(vid: int, target_name: String, level := -1, grade := -1, is_pc := false) -> void: _current_vid = vid _is_pc = is_pc var display_name := target_name var prefix := "" if level > 0: prefix += "[Lv. %d] " % level if grade in GRADE_NAMES: prefix += "(%s) " % GRADE_NAMES[grade] _current_name = prefix + display_name _name_label.text = _current_name # 40250 uitarget.py:301 板面自适应宽度:200 + 7 * nameLength var calculated_width := maxf(DEFAULT_BOARD_WIDTH, 200.0 + 7.0 * float(_current_name.length())) _update_layout(calculated_width, is_pc) _shown = true _root.visible = true _update_screen_position() func set_hp(hp_pct: int) -> void: _current_hp_pct = clampi(hp_pct, 0, 100) if _hp_gauge_fill: _hp_gauge_fill.size.x = GAUGE_WIDTH * (_current_hp_pct / 100.0) if _hp_text: _hp_text.text = "%d%%" % _current_hp_pct if _hp_gauge_bg and not _is_pc: _hp_gauge_bg.visible = true func close() -> void: _shown = false _current_vid = 0 _current_name = "" if _root: _root.visible = false func _on_close_button_pressed() -> void: if client and client.has_method("clear_target"): client.clear_target() close() func _update_layout(width: float, is_pc: bool) -> void: _board.size = Vector2(width, BOARD_HEIGHT) if is_pc: _hp_gauge_bg.visible = false _button_container.visible = true _button_container.position = Vector2(width - 200, 8) else: _hp_gauge_bg.visible = true _button_container.visible = false _hp_gauge_bg.position = Vector2(width - 175, 14) _close_button.position = Vector2(width - 28, 10) func _update_screen_position() -> void: if _root == null or not is_open(): return var screen_w := 800.0 var vp := _root.get_viewport() if vp: screen_w = vp.get_visible_rect().size.x # 40250 uitarget.py:254 UpdatePosition: ScreenWidth // 2 - Width // 2, 10 _root.position = Vector2(screen_w / 2.0 - _board.size.x / 2.0, 10.0) func _build(parent: Node) -> void: _root = Control.new() _root.name = "TargetBoard" _root.set_anchors_preset(Control.PRESET_TOP_LEFT) _root.size = Vector2(DEFAULT_BOARD_WIDTH, BOARD_HEIGHT) _root.visible = false parent.add_child(_root) # 经典 ThinBoard 风格 _board = Panel.new() _board.name = "Board" _board.size = Vector2(DEFAULT_BOARD_WIDTH, BOARD_HEIGHT) var bg := StyleBoxFlat.new() bg.bg_color = Color(0.04, 0.05, 0.07, 0.88) bg.border_color = Color(0.45, 0.38, 0.22, 0.95) bg.set_border_width_all(1) bg.set_corner_radius_all(2) _board.add_theme_stylebox_override("panel", bg) _root.add_child(_board) # 目标名称标签 _name_label = Label.new() _name_label.name = "Name" _name_label.position = Vector2(23, 11) _name_label.size = Vector2(200, 20) _name_label.add_theme_font_size_override("font_size", 11) _name_label.add_theme_color_override("font_color", Color(1.0, 0.92, 0.75)) _name_label.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.9)) _name_label.add_theme_constant_override("outline_size", 2) _board.add_child(_name_label) # 红色 HP Gauge(40250 130px 经典红槽) _hp_gauge_bg = ColorRect.new() _hp_gauge_bg.name = "HPGaugeBG" _hp_gauge_bg.position = Vector2(DEFAULT_BOARD_WIDTH - 175, 14) _hp_gauge_bg.size = Vector2(GAUGE_WIDTH, 12) _hp_gauge_bg.color = Color(0.12, 0.02, 0.02, 0.95) _board.add_child(_hp_gauge_bg) _hp_gauge_fill = ColorRect.new() _hp_gauge_fill.name = "HPGaugeFill" _hp_gauge_fill.position = Vector2.ZERO _hp_gauge_fill.size = Vector2(GAUGE_WIDTH, 12) _hp_gauge_fill.color = Color(0.85, 0.12, 0.12, 1.0) _hp_gauge_bg.add_child(_hp_gauge_fill) _hp_text = Label.new() _hp_text.name = "HPText" _hp_text.set_anchors_preset(Control.PRESET_FULL_RECT) _hp_text.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _hp_text.vertical_alignment = VERTICAL_ALIGNMENT_CENTER _hp_text.add_theme_font_size_override("font_size", 9) _hp_text.add_theme_color_override("font_color", Color(1, 1, 1, 0.95)) _hp_text.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.8)) _hp_text.add_theme_constant_override("outline_size", 1) _hp_text.text = "100%" _hp_gauge_bg.add_child(_hp_text) # 关闭按钮 (X) _close_button = Button.new() _close_button.name = "CloseButton" _close_button.position = Vector2(DEFAULT_BOARD_WIDTH - 28, 10) _close_button.size = Vector2(18, 18) _close_button.text = "×" _close_button.add_theme_font_size_override("font_size", 12) _close_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND _close_button.pressed.connect(_on_close_button_pressed) _board.add_child(_close_button) # PC 交互按钮条 _button_container = HBoxContainer.new() _button_container.name = "ButtonContainer" _button_container.position = Vector2(DEFAULT_BOARD_WIDTH - 200, 8) _button_container.visible = false _board.add_child(_button_container) _add_action_btn("私聊", func(): whisper_requested.emit(_current_name)) _add_action_btn("交易", func(): exchange_requested.emit(_current_vid)) _add_action_btn("装备", func(): view_equipment_requested.emit(_current_vid)) func _add_action_btn(text: String, callback: Callable) -> void: var btn := Button.new() btn.text = text btn.custom_minimum_size = Vector2(42, 22) btn.add_theme_font_size_override("font_size", 10) btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND btn.pressed.connect(callback) _button_container.add_child(btn)