From fc5afc8ca5a357aa879dc05b66f09cd40050eeae Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Tue, 13 Oct 2026 09:21:01 +0200 Subject: [PATCH] Update hints system --- game/mount/mount_rider.gd | 5 ++-- game/player/player_character.tscn | 4 +++ game/player/states/aim_state.gd | 12 ++++++--- game/player/states/dodge_state.gd | 3 --- game/player/states/idle_state.gd | 3 --- game/player/states/jump_state.gd | 2 -- game/player/states/run_state.gd | 3 --- game/player/states/state.gd | 7 ++++-- game/player/states/state_machine.gd | 16 +++++++++--- game/player/states/throw_state.gd | 6 ++--- game/player/states/walk_state.gd | 2 -- game/ui/hints/hints.gd | 38 ++++++++++++++++++++--------- 12 files changed, 61 insertions(+), 40 deletions(-) diff --git a/game/mount/mount_rider.gd b/game/mount/mount_rider.gd index 1ec9db6..b448075 100644 --- a/game/mount/mount_rider.gd +++ b/game/mount/mount_rider.gd @@ -22,7 +22,6 @@ signal candidate_changed(sent : SentPokemon) #pokemon montable a portee (null = @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 @@ -70,7 +69,7 @@ func is_mounted() -> bool: func _physics_process(_delta : float) -> void: if mount != null: var can_dismount : bool = _can_switch_now() - if can_dismount: Hints.set_context(self, dismount_action, dismount_hint_text, hint_priority) + if can_dismount: Hints.set_context(self, dismount_action, "", hint_priority) else: Hints.clear_context(self) if Input.is_action_just_pressed(dismount_action) and can_dismount: dismount() @@ -146,7 +145,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) + Hints.set_context(self, dismount_action, "", hint_priority) player.is_mounted = true player.enter_mount_stats(profile.mount_speed, profile.mount_accel, profile.mount_deccel, diff --git a/game/player/player_character.tscn b/game/player/player_character.tscn index e40f0c3..87f8a5f 100644 --- a/game/player/player_character.tscn +++ b/game/player/player_character.tscn @@ -81,12 +81,15 @@ initial_state = NodePath("IdleState") [node name="IdleState" type="Node" parent="StateMachine" unique_id=1417869633] script = ExtResource("4_38lxl") +hints = Array[StringName]([&"player_jump"]) [node name="WalkState" type="Node" parent="StateMachine" unique_id=1524475809] script = ExtResource("4_lg056") +hints = Array[StringName]([&"player_jump"]) [node name="JumpState" type="Node" parent="StateMachine" unique_id=711160985] script = ExtResource("6_lwgph") +hints = Array[StringName]([&"player_jump"]) [node name="AimState" type="Node" parent="StateMachine" unique_id=296560188] script = ExtResource("7_kxr4l") @@ -96,6 +99,7 @@ script = ExtResource("8_k0r6x") [node name="RunState" type="Node" parent="StateMachine" unique_id=1345421775] script = ExtResource("8_j4mf1") +hints = Array[StringName]([&"player_jump"]) [node name="DodgeState" type="Node" parent="StateMachine" unique_id=232179400] script = ExtResource("9_6abew") diff --git a/game/player/states/aim_state.gd b/game/player/states/aim_state.gd index 874736f..d3df3c8 100644 --- a/game/player/states/aim_state.gd +++ b/game/player/states/aim_state.gd @@ -28,7 +28,11 @@ var auto_lock_blocked : bool = false #true apres un deverrouillage manuel, tant var dodging_from_aim : bool = false #true quand on quitte Aim pour rouler, pour ne pas relacher la cible verrouillee var came_from_crouch : bool = false #true si Aim a ete declenche depuis CrouchState, pour y retourner en sortant var keep_aim_on_exit : bool = false #true quand on part vers ThrowState : camera et verrouillage restent en place -var charging_throw : bool = false #true quand on arrive depuis ThrowState en pleine charge : RT est encore maintenue +var charging_throw : bool = false: #true quand on arrive depuis ThrowState en pleine charge : RT est encore maintenue + set(value): + if charging_throw == value: return + charging_throw = value + hints_changed.emit() func _ready() -> void: if InputMap.has_action(throw_action): return @@ -236,6 +240,6 @@ func release_target() -> void: play_char.cam_holder.set_lock_target(null) func get_hints() -> Array: - return [ - {"action": switch_target_action, "text": "Changer de cible"} - ] + var list : Array[StringName] = [switch_target_action] + if charging_throw: list.append(cancel_action) + return list diff --git a/game/player/states/dodge_state.gd b/game/player/states/dodge_state.gd index e3b2781..16465ec 100644 --- a/game/player/states/dodge_state.gd +++ b/game/player/states/dodge_state.gd @@ -90,6 +90,3 @@ func end_dodge() -> void: transitioned.emit(self, play_char.walk_or_run) else: transitioned.emit(self, "IdleState") - -func get_hints() -> Variant: - return null diff --git a/game/player/states/idle_state.gd b/game/player/states/idle_state.gd index 7080ed5..34491dd 100644 --- a/game/player/states/idle_state.gd +++ b/game/player/states/idle_state.gd @@ -70,6 +70,3 @@ 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 d00b50c..667fdd9 100644 --- a/game/player/states/jump_state.gd +++ b/game/player/states/jump_state.gd @@ -110,5 +110,3 @@ 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() -> Variant: - return null diff --git a/game/player/states/run_state.gd b/game/player/states/run_state.gd index 9b89694..59c630e 100644 --- a/game/player/states/run_state.gd +++ b/game/player/states/run_state.gd @@ -68,6 +68,3 @@ func move(delta : float) -> void: else: if !play_char.continious_run: play_char.walk_or_run = "WalkState" transitioned.emit(self, "IdleState") - -func get_hints() -> Variant: - return null diff --git a/game/player/states/state.gd b/game/player/states/state.gd index ee453f6..b3c7333 100644 --- a/game/player/states/state.gd +++ b/game/player/states/state.gd @@ -3,6 +3,9 @@ extends Node class_name State signal transitioned #it's normal if this signal isn't used in this script, because it's purpose is to be used in the scripts that extends from the State class +signal hints_changed #à émettre quand get_hints() change pendant que l'état est actif + +@export var hints : Array[StringName] = [] #hints simples, réglables dans l'inspecteur func enter(_char_reference : CharacterBody3D) -> void: #enter state @@ -20,5 +23,5 @@ func physics_update(_delta : float) -> void: #physics_process update pass -func get_hints() -> Variant: - return [] +func get_hints() -> Array: + return hints #à surcharger seulement si les hints dépendent d'une condition diff --git a/game/player/states/state_machine.gd b/game/player/states/state_machine.gd index ecb5d14..fba5287 100644 --- a/game/player/states/state_machine.gd +++ b/game/player/states/state_machine.gd @@ -20,6 +20,7 @@ func _ready() -> void: if child is State: states[child.name.to_lower()] = child child.transitioned.connect(on_state_child_transition) + child.hints_changed.connect(_on_hints_changed.bind(child)) #if initial state, transition to it if initial_state: @@ -27,8 +28,7 @@ func _ready() -> void: initial_state.enter(char_ref) curr_state = initial_state curr_state_name = curr_state.state_name - var hints = curr_state.get_hints() - if hints != null: Hints.set_state_hints(hints) + publish_hints() func _process(delta : float) -> void: if curr_state: curr_state.update(delta) @@ -75,9 +75,17 @@ func on_state_child_transition(state : State, new_state_name : String) -> void: curr_state = new_state curr_state_name = curr_state.state_name - var hints = curr_state.get_hints() - if hints != null: Hints.set_state_hints(hints) + publish_hints() func set_state_blocked(state_name : String, blocked : bool) -> void: if blocked: blocked_states[state_name.to_lower()] = true else: blocked_states.erase(state_name.to_lower()) + +func _on_hints_changed(state : State) -> void: + if state == curr_state: publish_hints() + +func publish_hints() -> void: + if !curr_state: return + var actions = curr_state.get_hints() + if actions != null: Hints.set_state_hints(actions) #null = on garde les hints précédents (si tu as gardé cette option pour Dodge) + diff --git a/game/player/states/throw_state.gd b/game/player/states/throw_state.gd index b5697bc..1f660c4 100644 --- a/game/player/states/throw_state.gd +++ b/game/player/states/throw_state.gd @@ -296,6 +296,6 @@ func _release_aim() -> void: play_char.cam_holder.cam_aimed = false func get_hints() -> Array: - return [ - {"action": cancel_action, "text": "Annuler le lancer"}, - ] + var list : Array[StringName] = [] + if !_thrown: list.append(cancel_action) #plus d'annulation possible une fois la balle partie + return list diff --git a/game/player/states/walk_state.gd b/game/player/states/walk_state.gd index 6725b6f..5dd8b02 100644 --- a/game/player/states/walk_state.gd +++ b/game/player/states/walk_state.gd @@ -71,5 +71,3 @@ func move(delta : float) -> void: else: transitioned.emit(self, "IdleState") -func get_hints() -> Variant: - return null diff --git a/game/ui/hints/hints.gd b/game/ui/hints/hints.gd index d309c05..fe2b4a1 100644 --- a/game/ui/hints/hints.gd +++ b/game/ui/hints/hints.gd @@ -2,32 +2,44 @@ extends Node signal changed -var _state_hints : Array = [] # [{action, text}] -var _context_hints : Dictionary = {} # clé (objet source) -> {action, text, priority} +#catalogue unique : action -> libellé affiché +const LABELS : Dictionary = { + &"player_jump": "Sauter", + &"player_dismount": "Descendre", + &"player_aim_switch_target": "Changer de cible", + &"player_aim_unlock": "Libérer la cible", + &"player_throw_cancel": "Annuler le lancer", +} + +var _state_actions : Array = [] # [action, ...] +var _context_hints : Dictionary = {} # clé (objet ou StringName) -> {action, text, priority} + +func label_for(action : StringName) -> String: + return LABELS.get(action, String(action)) #sans entrée : le nom de l'action, bien visible #---------- hints d'état (appelés par la StateMachine) ---------- -func set_state_hints(list : Array) -> void: - _state_hints = list +func set_state_hints(actions : Array) -> void: + _state_actions = actions changed.emit() -#---------- hints de contexte (appelés par monture, PNJ, etc.) ---------- +#---------- hints de contexte (monture, PNJ, etc.) ---------- +#text vide : le libellé vient du catalogue. À renseigner quand le sens dépend du contexte (Grimper / Parler sur la même action) -func set_context(source : Object, action : StringName, text : String, priority : int = 0) -> void: - var h : Dictionary = {"action": action, "text": text, "priority": priority} +func set_context(source : Variant, action : StringName, text : String = "", priority : int = 0) -> void: + var h : Dictionary = {"action": action, "text": text if text != "" else label_for(action), "priority": priority} if _context_hints.get(source) == h: return _context_hints[source] = h changed.emit() -func clear_context(source : Object) -> void: +func clear_context(source : Variant) -> 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) + if typeof(key) == TYPE_OBJECT and !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) @@ -35,8 +47,12 @@ func get_visible() -> Array: #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: + for h in ctx: if used.has(h.action): continue used[h.action] = true result.append(h) + for action in _state_actions: + if used.has(action): continue + used[action] = true + result.append({"action": action, "text": label_for(action)}) return result