From e1152001941c7afceaffa13e8896ecf8ef151df6 Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Tue, 13 Oct 2026 08:55:12 +0200 Subject: [PATCH] Add ui hints --- game/mount/mount_rider.gd | 17 +++++++- game/player/states/aim_state.gd | 5 +++ game/player/states/idle_state.gd | 3 ++ game/player/states/jump_state.gd | 3 +- game/player/states/mounted_state.gd | 3 ++ game/player/states/run_state.gd | 3 ++ game/player/states/state.gd | 3 ++ game/player/states/state_machine.gd | 2 + game/player/states/throw_state.gd | 5 +++ game/player/states/walk_state.gd | 2 + game/ui/hints/hints.gd | 42 ++++++++++++++++++ game/ui/hints/hints.gd.uid | 1 + game/ui/hints/hints_hud.gd | 33 +++++++++++++++ game/ui/hints/hints_hud.gd.uid | 1 + game/ui/hud/ui.tscn | 66 ++--------------------------- project.godot | 1 + 16 files changed, 125 insertions(+), 65 deletions(-) create mode 100644 game/ui/hints/hints.gd create mode 100644 game/ui/hints/hints.gd.uid create mode 100644 game/ui/hints/hints_hud.gd create mode 100644 game/ui/hints/hints_hud.gd.uid diff --git a/game/mount/mount_rider.gd b/game/mount/mount_rider.gd index 18528c4..1ec9db6 100644 --- a/game/mount/mount_rider.gd +++ b/game/mount/mount_rider.gd @@ -20,6 +20,11 @@ signal candidate_changed(sent : SentPokemon) #pokemon montable a portee (null = @export var swallow_jump_on_mount : bool = true #si A sert aussi a sauter : l'appui qui monte ne declenche pas de saut @export var camera_follow_speed : float = 8.0 #vitesse a laquelle la camera monte a hauteur de selle +@export_group("Hints HUD") +@export var mount_hint_text : String = "Grimper" +@export var dismount_hint_text : String = "Descendre" +@export var hint_priority : int = 10 + const GROUNDED_STATES : Array[String] = ["Idle", "Walk", "Run"] #monter / descendre n'est possible que depuis ces etats @onready var player : PlayerCharacter = get_parent() @@ -51,6 +56,9 @@ func _ready() -> void: key.physical_keycode = KEY_F InputMap.action_add_event(dismount_action, key)) +func _exit_tree() -> void: + Hints.clear_context(self) + func _ensure_action(action : StringName, add_events : Callable) -> void: if InputMap.has_action(action): return InputMap.add_action(action) @@ -61,7 +69,10 @@ func is_mounted() -> bool: func _physics_process(_delta : float) -> void: if mount != null: - if Input.is_action_just_pressed(dismount_action) and _can_switch_now(): + var can_dismount : bool = _can_switch_now() + if can_dismount: Hints.set_context(self, dismount_action, dismount_hint_text, hint_priority) + else: Hints.clear_context(self) + if Input.is_action_just_pressed(dismount_action) and can_dismount: dismount() return @@ -123,6 +134,8 @@ func _set_candidate(s : SentPokemon) -> void: if s == candidate: return candidate = s candidate_changed.emit(s) + if s != null: Hints.set_context(self, mount_action, mount_hint_text, hint_priority) + else: Hints.clear_context(self) #---------- monter / descendre ---------- @@ -133,6 +146,7 @@ func mount_up(s : SentPokemon) -> void: s.rider = player s.recalled.connect(_on_mount_recalled) _set_candidate(null) + Hints.set_context(self, dismount_action, dismount_hint_text, hint_priority) player.is_mounted = true player.enter_mount_stats(profile.mount_speed, profile.mount_accel, profile.mount_deccel, @@ -151,6 +165,7 @@ func dismount() -> void: player.is_mounted = false player.exit_mount_stats() + Hints.clear_context(self) _release_blocked_states_next_frame() visual_root.position -= _seat_applied diff --git a/game/player/states/aim_state.gd b/game/player/states/aim_state.gd index ab6145a..874736f 100644 --- a/game/player/states/aim_state.gd +++ b/game/player/states/aim_state.gd @@ -234,3 +234,8 @@ func release_target() -> void: if is_instance_valid(play_char.aim_target): play_char.aim_target.set_locked(false) play_char.aim_target = null play_char.cam_holder.set_lock_target(null) + +func get_hints() -> Array: + return [ + {"action": switch_target_action, "text": "Changer de cible"} + ] diff --git a/game/player/states/idle_state.gd b/game/player/states/idle_state.gd index 34491dd..7080ed5 100644 --- a/game/player/states/idle_state.gd +++ b/game/player/states/idle_state.gd @@ -70,3 +70,6 @@ func move(delta : float) -> void: #apply smooth stop play_char.velocity.x = lerp(play_char.velocity.x, 0.0, play_char.move_deccel * delta) play_char.velocity.z = lerp(play_char.velocity.z, 0.0, play_char.move_deccel * delta) + +func get_hints() -> Array: + return [{"action": &"player_jump", "text": "Sauter"}] diff --git a/game/player/states/jump_state.gd b/game/player/states/jump_state.gd index 4375a73..9a089cb 100644 --- a/game/player/states/jump_state.gd +++ b/game/player/states/jump_state.gd @@ -110,4 +110,5 @@ func jump() -> void: play_char.squash_and_strech(1.12, 0.1) #play_char.particles_manager.display_particles(play_char.jump_particles, play_char) - +func get_hints() -> Array: + return [{"action": &"player_jump", "text": "Sauter"}] diff --git a/game/player/states/mounted_state.gd b/game/player/states/mounted_state.gd index 3b6a1f4..1760aca 100644 --- a/game/player/states/mounted_state.gd +++ b/game/player/states/mounted_state.gd @@ -14,3 +14,6 @@ func enter(play_char_ref : CharacterBody3D) -> void: play_char.move_deccel = profile.mount_deccel # instancier profile.mount_scene_override ou profile.species.model_scene, # le positionner, y attacher play_char selon seat_offset... + +func get_hints() -> Array: + return [{"action": &"player_dismount", "text": "Descendre"}] # remplace par le nom réel de ton action diff --git a/game/player/states/run_state.gd b/game/player/states/run_state.gd index 59c630e..cf5eb78 100644 --- a/game/player/states/run_state.gd +++ b/game/player/states/run_state.gd @@ -68,3 +68,6 @@ func move(delta : float) -> void: else: if !play_char.continious_run: play_char.walk_or_run = "WalkState" transitioned.emit(self, "IdleState") + +func get_hints() -> Array: + return [{"action": &"player_jump", "text": "Sauter"}] diff --git a/game/player/states/state.gd b/game/player/states/state.gd index df25be5..b06dd71 100644 --- a/game/player/states/state.gd +++ b/game/player/states/state.gd @@ -19,3 +19,6 @@ func update(_delta : float) -> void: func physics_update(_delta : float) -> void: #physics_process update pass + +func get_hints() -> Array: + return [] diff --git a/game/player/states/state_machine.gd b/game/player/states/state_machine.gd index e5d226c..8132310 100644 --- a/game/player/states/state_machine.gd +++ b/game/player/states/state_machine.gd @@ -27,6 +27,7 @@ func _ready() -> void: initial_state.enter(char_ref) curr_state = initial_state curr_state_name = curr_state.state_name + Hints.set_state_hints(curr_state.get_hints()) func _process(delta : float) -> void: if curr_state: curr_state.update(delta) @@ -73,6 +74,7 @@ func on_state_child_transition(state : State, new_state_name : String) -> void: curr_state = new_state curr_state_name = curr_state.state_name + Hints.set_state_hints(curr_state.get_hints()) func set_state_blocked(state_name : String, blocked : bool) -> void: if blocked: blocked_states[state_name.to_lower()] = true diff --git a/game/player/states/throw_state.gd b/game/player/states/throw_state.gd index 494ace9..b5697bc 100644 --- a/game/player/states/throw_state.gd +++ b/game/player/states/throw_state.gd @@ -294,3 +294,8 @@ func _release_aim() -> void: play_char.aim_target = null play_char.cam_holder.set_lock_target(null) play_char.cam_holder.cam_aimed = false + +func get_hints() -> Array: + return [ + {"action": cancel_action, "text": "Annuler le lancer"}, + ] diff --git a/game/player/states/walk_state.gd b/game/player/states/walk_state.gd index 5dd8b02..544710f 100644 --- a/game/player/states/walk_state.gd +++ b/game/player/states/walk_state.gd @@ -71,3 +71,5 @@ func move(delta : float) -> void: else: transitioned.emit(self, "IdleState") +func get_hints() -> Array: + return [{"action": &"player_jump", "text": "Sauter"}] diff --git a/game/ui/hints/hints.gd b/game/ui/hints/hints.gd new file mode 100644 index 0000000..d309c05 --- /dev/null +++ b/game/ui/hints/hints.gd @@ -0,0 +1,42 @@ +extends Node + +signal changed + +var _state_hints : Array = [] # [{action, text}] +var _context_hints : Dictionary = {} # clé (objet source) -> {action, text, priority} + +#---------- hints d'état (appelés par la StateMachine) ---------- + +func set_state_hints(list : Array) -> void: + _state_hints = list + changed.emit() + +#---------- hints de contexte (appelés par monture, PNJ, etc.) ---------- + +func set_context(source : Object, action : StringName, text : String, priority : int = 0) -> void: + var h : Dictionary = {"action": action, "text": text, "priority": priority} + if _context_hints.get(source) == h: return + _context_hints[source] = h + changed.emit() + +func clear_context(source : Object) -> void: + if _context_hints.erase(source): changed.emit() + +#---------- lecture (par le HUD) ---------- + +func get_visible() -> Array: + #nettoie les sources détruites sans avoir appelé clear_context + for key in _context_hints.keys(): + if !is_instance_valid(key): _context_hints.erase(key) + + var ctx : Array = _context_hints.values() + ctx.sort_custom(func(a, b): return a.priority > b.priority) + + #le contexte passe avant l'état ; une même action n'apparaît qu'une fois + var result : Array = [] + var used : Dictionary = {} + for h in ctx + _state_hints: + if used.has(h.action): continue + used[h.action] = true + result.append(h) + return result diff --git a/game/ui/hints/hints.gd.uid b/game/ui/hints/hints.gd.uid new file mode 100644 index 0000000..1b4b3ec --- /dev/null +++ b/game/ui/hints/hints.gd.uid @@ -0,0 +1 @@ +uid://bqapxkrub0fcs diff --git a/game/ui/hints/hints_hud.gd b/game/ui/hints/hints_hud.gd new file mode 100644 index 0000000..4a0263f --- /dev/null +++ b/game/ui/hints/hints_hud.gd @@ -0,0 +1,33 @@ +extends MarginContainer + +@onready var rows : HBoxContainer = $HBoxContainer + +func _ready() -> void: + Hints.changed.connect(refresh) + refresh() + +func refresh() -> void: + for c in rows.get_children(): + rows.remove_child(c) + c.queue_free() + for h in Hints.get_visible(): + rows.add_child(make_row(h.action, h.text)) + +func make_row(action : StringName, text : String) -> HBoxContainer: + var row := HBoxContainer.new() + + var tex := ControllerIconTexture.new() + tex.path = String(action) #même chose que le champ "path" dans ta scène + + var icon := TextureRect.new() + icon.texture = tex + icon.custom_minimum_size = Vector2(40, 40) + icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + row.add_child(icon) + + var label := Label.new() + label.text = text + label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + row.add_child(label) + return row diff --git a/game/ui/hints/hints_hud.gd.uid b/game/ui/hints/hints_hud.gd.uid new file mode 100644 index 0000000..db48999 --- /dev/null +++ b/game/ui/hints/hints_hud.gd.uid @@ -0,0 +1 @@ +uid://cj73boctbuqvj diff --git a/game/ui/hud/ui.tscn b/game/ui/hud/ui.tscn index fe38ced..7f12577 100644 --- a/game/ui/hud/ui.tscn +++ b/game/ui/hud/ui.tscn @@ -1,30 +1,10 @@ [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://rgm6aitwyxdv" path="res://game/ui/hud/save_hud.gd" id="1_euh0j"] +[ext_resource type="Script" uid="uid://cj73boctbuqvj" path="res://game/ui/hints/hints_hud.gd" id="2_8ujol"] [ext_resource type="Script" uid="uid://b3ddqgiawrh5c" path="res://game/ui/hud/team_hud.gd" id="2_lkjh2"] [ext_resource type="Script" uid="uid://c3b263k0gt0ck" path="res://game/ui/hide_during_battle.gd" id="3_8ujol"] -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_uyiaf"] - -[sub_resource type="Texture2D" id="Texture2D_3agn1"] -resource_local_to_scene = false -resource_name = "" -script = ExtResource("1_4xhdt") -path = "player_jump" -metadata/_custom_type_script = "uid://7hglx6nfu063" - -[sub_resource type="LabelSettings" id="LabelSettings_3agn1"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0fvdv"] - -[sub_resource type="Texture2D" id="Texture2D_4xhdt"] -resource_local_to_scene = false -resource_name = "" -script = ExtResource("1_4xhdt") -path = "ui_accept" -metadata/_custom_type_script = "uid://7hglx6nfu063" - [node name="Ui" type="CanvasLayer" unique_id=1492671226] [node name="SaveHUD" type="CanvasLayer" parent="." unique_id=319200051] @@ -49,53 +29,13 @@ grow_horizontal = 0 grow_vertical = 0 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 +script = ExtResource("2_8ujol") [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer" unique_id=1235437041] layout_mode = 2 - -[node name="PanelContainer2" type="PanelContainer" parent="MarginContainer/HBoxContainer" unique_id=429339024] -layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_uyiaf") - -[node name="HFlowContainer3" type="HFlowContainer" parent="MarginContainer/HBoxContainer/PanelContainer2" unique_id=165290387] -custom_minimum_size = Vector2(130, -1) -layout_mode = 2 +theme_override_constants/separation = 24 alignment = 2 -[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer/PanelContainer2/HFlowContainer3" unique_id=895869050] -custom_minimum_size = Vector2(40, 40) -custom_maximum_size = Vector2(40, 40) -layout_mode = 2 -size_flags_vertical = 3 -texture = SubResource("Texture2D_3agn1") -expand_mode = 1 - -[node name="Label" type="Label" parent="MarginContainer/HBoxContainer/PanelContainer2/HFlowContainer3" unique_id=1494282096] -layout_mode = 2 -text = "Sauter" -label_settings = SubResource("LabelSettings_3agn1") - -[node name="PanelContainer" type="PanelContainer" parent="MarginContainer/HBoxContainer" unique_id=525836706] -layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_0fvdv") - -[node name="HFlowContainer2" type="HFlowContainer" parent="MarginContainer/HBoxContainer/PanelContainer" unique_id=534508482] -custom_minimum_size = Vector2(130, -1) -layout_mode = 2 -alignment = 2 - -[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer/PanelContainer/HFlowContainer2" unique_id=729252705] -custom_minimum_size = Vector2(40, 40) -layout_mode = 2 -size_flags_vertical = 3 -texture = SubResource("Texture2D_4xhdt") -expand_mode = 1 - -[node name="Label" type="Label" parent="MarginContainer/HBoxContainer/PanelContainer/HFlowContainer2" unique_id=701166371] -layout_mode = 2 -text = "Accepter" -label_settings = SubResource("LabelSettings_3agn1") - [node name="HideDuringBattle" type="Node" parent="MarginContainer" unique_id=1229951221] script = ExtResource("3_8ujol") diff --git a/project.godot b/project.godot index 75aeaa3..041179d 100644 --- a/project.godot +++ b/project.godot @@ -27,6 +27,7 @@ ControllerIcons="*uid://b7ho1rjcpht1d" GameData="*uid://d4beiel88cwc7" UiAudio="*uid://7e7fe2xk3aue" LoadingScreen="*uid://ckyjxhrfhaqlc" +Hints="*uid://bqapxkrub0fcs" Pokedex="*uid://dijnkrewbwgmx" MountRegistry="*uid://u4gskwbwm0b0" DebugPokemonPanel="*uid://b3058rssf6ud5"