diff --git a/game/ui/hud/team_hud.gd b/game/ui/hud/team_hud.gd new file mode 100644 index 0000000..6acd782 --- /dev/null +++ b/game/ui/hud/team_hud.gd @@ -0,0 +1,208 @@ +class_name TeamHUD +extends Control + +#element de HUD : barre de l'equipe en bas a gauche ; le pokemon selectionne est agrandi. +#la selection est stockee dans GameData (GameData.get_selected_pokemon()), +#pour que le lancer (ThrowState...) sache quel pokemon envoyer. +# +#usage : ajouter TeamHUD.new() a ton HUD (CanvasLayer), ou attacher ce script a un Control plein ecran. + +const ControllerIconTextureScript = preload("res://addons/controller_icons/objects/ControllerIconTexture.gd") + +#actions creees automatiquement si elles n'existent pas (croix gauche/droite, fleches du clavier) +@export var prev_action : StringName = &"hud_team_prev" +@export var next_action : StringName = &"hud_team_next" +@export var slot_size : float = 68.0 +@export var selected_slot_size : float = 90.0 + +var _root_box : MarginContainer +var _name_label : Label +var _prev_icon : TextureRect +var _next_icon : TextureRect + +var _slot_panels : Array[PanelContainer] = [] +var _slot_styles : Array[StyleBoxFlat] = [] +var _slot_sprites : Array[TextureRect] = [] +var _slot_bars : Array[ProgressBar] = [] +var _slot_fills : Array[StyleBoxFlat] = [] +var _signatures : Array = [] #evite de reappliquer l'affichage d'un emplacement qui n'a pas change + +func _ready() -> void: + _ensure_actions() + _build_ui() + +#---------- actions d'entree ---------- + +func _ensure_actions() -> void: + _ensure_action(prev_action, [_joy_event(JOY_BUTTON_DPAD_LEFT), _key_event(KEY_LEFT)]) + _ensure_action(next_action, [_joy_event(JOY_BUTTON_DPAD_RIGHT), _key_event(KEY_RIGHT)]) + +func _ensure_action(action : StringName, events : Array[InputEvent]) -> void: + if InputMap.has_action(action): return + InputMap.add_action(action) + for e in events: InputMap.action_add_event(action, e) + +func _joy_event(button : JoyButton) -> InputEvent: + var e := InputEventJoypadButton.new() + e.button_index = button + return e + +func _key_event(key : Key) -> InputEvent: + var e := InputEventKey.new() + e.physical_keycode = key + return e + +func _unhandled_input(event : InputEvent) -> void: + #n'est pas appele quand le jeu est en pause (menu pause ouvert) + if event.is_action_pressed(prev_action): + GameData.cycle_selection(-1) + get_viewport().set_input_as_handled() + elif event.is_action_pressed(next_action): + GameData.cycle_selection(1) + get_viewport().set_input_as_handled() + +#---------- construction ---------- + +func _build_ui() -> void: + set_anchors_preset(Control.PRESET_FULL_RECT) + mouse_filter = Control.MOUSE_FILTER_IGNORE + + _root_box = MarginContainer.new() + _root_box.set_anchors_preset(Control.PRESET_BOTTOM_LEFT) + _root_box.grow_vertical = Control.GROW_DIRECTION_BEGIN #grandit vers le haut + _root_box.mouse_filter = Control.MOUSE_FILTER_IGNORE + for side in ["left", "bottom"]: + _root_box.add_theme_constant_override("margin_" + side, 32) + add_child(_root_box) + + var column := VBoxContainer.new() + column.mouse_filter = Control.MOUSE_FILTER_IGNORE + column.add_theme_constant_override("separation", 6) + _root_box.add_child(column) + + _name_label = Label.new() + _name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE + _name_label.add_theme_font_size_override("font_size", 20) + _name_label.add_theme_constant_override("outline_size", 6) + _name_label.add_theme_color_override("font_outline_color", Color.BLACK) + column.add_child(_name_label) + + var row := HBoxContainer.new() + row.mouse_filter = Control.MOUSE_FILTER_IGNORE + row.add_theme_constant_override("separation", 8) + column.add_child(row) + + _prev_icon = _make_hint_icon(prev_action) + row.add_child(_prev_icon) + + var slots_row := HBoxContainer.new() + slots_row.mouse_filter = Control.MOUSE_FILTER_IGNORE + slots_row.add_theme_constant_override("separation", 6) + row.add_child(slots_row) + for i in PokemonTeam.MAX_SIZE: + _add_slot(slots_row) + _signatures.append(null) + + _next_icon = _make_hint_icon(next_action) + row.add_child(_next_icon) + +func _add_slot(parent : Control) -> void: + var panel := PanelContainer.new() + panel.mouse_filter = Control.MOUSE_FILTER_IGNORE + panel.size_flags_vertical = Control.SIZE_SHRINK_END #les petits restent alignes en bas, le selectionne depasse vers le haut + var style := StyleBoxFlat.new() + style.bg_color = Color(0, 0, 0, 0.55) + style.set_corner_radius_all(10) + style.set_border_width_all(2) + style.set_content_margin_all(6) + panel.add_theme_stylebox_override("panel", style) + parent.add_child(panel) + + var box := VBoxContainer.new() + box.mouse_filter = Control.MOUSE_FILTER_IGNORE + box.add_theme_constant_override("separation", 3) + panel.add_child(box) + + var sprite := TextureRect.new() + sprite.mouse_filter = Control.MOUSE_FILTER_IGNORE + sprite.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + sprite.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + sprite.size_flags_vertical = Control.SIZE_EXPAND_FILL + box.add_child(sprite) + + var bar := ProgressBar.new() + bar.mouse_filter = Control.MOUSE_FILTER_IGNORE + bar.show_percentage = false + bar.custom_minimum_size = Vector2(0, 6) + var fill := StyleBoxFlat.new() + fill.bg_color = Color(0.3, 0.8, 0.35) + bar.add_theme_stylebox_override("fill", fill) + box.add_child(bar) + + _slot_panels.append(panel) + _slot_styles.append(style) + _slot_sprites.append(sprite) + _slot_bars.append(bar) + _slot_fills.append(fill) + +func _make_hint_icon(action : StringName) -> TextureRect: + #icone de touche qui s'adapte au peripherique (addon controller_icons) + var tr := TextureRect.new() + tr.mouse_filter = Control.MOUSE_FILTER_IGNORE + var tex : Texture2D = ControllerIconTextureScript.new() + tex.set("path", String(action)) + tr.texture = tex + tr.custom_minimum_size = Vector2(32, 32) + tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + tr.size_flags_vertical = Control.SIZE_SHRINK_CENTER + return tr + +#---------- mise a jour (l'equipe change souvent : on lit l'etat chaque frame, sans signaux a rebrancher) ---------- + +func _process(_delta : float) -> void: + var team : PokemonTeam = GameData.player_team + GameData.validate_selection() + var selected : int = GameData.selected_index + + _root_box.visible = !team.is_empty() + var able_count : int = 0 + + for i in _slot_panels.size(): + var p : PokemonInstance = team.get_pokemon(i) + if p == null: + _slot_panels[i].visible = false + _signatures[i] = null + continue + + _slot_panels[i].visible = true + if !p.is_fainted(): able_count += 1 + + var sig : Array = [p.get_instance_id(), p.current_hp, p.get_max_hp(), i == selected] + if _signatures[i] == sig: continue + _signatures[i] = sig + _apply_slot(i, p, i == selected) + + #les icones de touches n'apparaissent que s'il y a un choix a faire + _prev_icon.visible = able_count > 1 + _next_icon.visible = able_count > 1 + + var selected_pokemon : PokemonInstance = team.get_pokemon(selected) + var label_text : String = "" + if selected_pokemon: label_text = "%s Niv.%d" % [selected_pokemon.get_display_name(), selected_pokemon.level] + if _name_label.text != label_text: _name_label.text = label_text + +func _apply_slot(i : int, p : PokemonInstance, is_selected : bool) -> void: + var px : float = selected_slot_size if is_selected else slot_size + _slot_panels[i].custom_minimum_size = Vector2(px, px) + _slot_panels[i].modulate = Color(1.0, 0.55, 0.55) if p.is_fainted() else Color.WHITE + _slot_sprites[i].texture = p.species.get_menu_sprite(false) + + _slot_styles[i].border_color = Color(1.0, 0.9, 0.4) if is_selected else Color(1, 1, 1, 0.25) + _slot_styles[i].set_border_width_all(3 if is_selected else 2) + + var max_hp : int = p.get_max_hp() + _slot_bars[i].max_value = max_hp + _slot_bars[i].value = p.current_hp + var ratio : float = float(p.current_hp) / float(max_hp) + _slot_fills[i].bg_color = Color(0.3, 0.8, 0.35) if ratio > 0.5 else (Color(0.95, 0.7, 0.2) if ratio > 0.2 else Color(0.9, 0.25, 0.25)) diff --git a/game/ui/hud/team_hud.gd.uid b/game/ui/hud/team_hud.gd.uid new file mode 100644 index 0000000..0ad9f5f --- /dev/null +++ b/game/ui/hud/team_hud.gd.uid @@ -0,0 +1 @@ +uid://b3ddqgiawrh5c diff --git a/game/ui/hud/ui.tscn b/game/ui/hud/ui.tscn index e9ecc56..85f86b3 100644 --- a/game/ui/hud/ui.tscn +++ b/game/ui/hud/ui.tscn @@ -1,6 +1,7 @@ [gd_scene format=3 uid="uid://di22cs2qposdm"] [ext_resource type="Script" uid="uid://7hglx6nfu063" path="res://addons/controller_icons/objects/ControllerIconTexture.gd" id="1_4xhdt"] +[ext_resource type="Script" uid="uid://b3ddqgiawrh5c" path="res://game/ui/hud/team_hud.gd" id="2_lkjh2"] [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_uyiaf"] @@ -82,3 +83,12 @@ expand_mode = 1 layout_mode = 2 text = "Accepter" label_settings = SubResource("LabelSettings_3agn1") + +[node name="TeamHud" type="Control" parent="." unique_id=687093905] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("2_lkjh2")