extends State class_name DodgeState var state_name : String = "Dodge" var play_char : CharacterBody3D @export var dodge_speed_curve : Curve #optionnel : controle le "falloff" de vitesse pendant la roulade (1.0 = pleine vitesse, 0.0 = arret). Laisser vide pour une vitesse constante. var dodge_dir : Vector2 = Vector2.ZERO var dodge_timer : float = 0.0 var dodge_duration_ref : float = 0.0 var came_from_crouch : bool = false #true si l'esquive vient du crouch (directement, ou via Aim declenche depuis le crouch) func enter(play_char_ref : CharacterBody3D) -> void: play_char = play_char_ref #curr_state_name n'est pas encore mis a jour a ce stade : il reflete encore l'etat qu'on quitte var previous : String = play_char.state_machine.curr_state_name if previous == "Crouch": came_from_crouch = true elif previous == "Aim": var aim : Node = play_char.state_machine.states.get("aimstate") came_from_crouch = aim != null and aim.came_from_crouch else: came_from_crouch = false verifications() func verifications() -> void: play_char.floor_snap_length = 1.0 play_char.is_dodging = true play_char.dodge_cooldown = play_char.dodge_cooldown_ref #roule dans la direction actuelle de l'input, ou dans la derniere direction connue si aucune touche n'est tenue (comportement Arceus) dodge_dir = play_char.move_dir if play_char.move_dir != Vector2.ZERO else play_char.last_input_dir if dodge_dir == Vector2.ZERO: dodge_dir = Vector2.DOWN #direction par defaut si le perso n'a encore jamais bouge dodge_dir = dodge_dir.normalized() dodge_timer = play_char.dodge_duration dodge_duration_ref = play_char.dodge_duration #oriente immediatement le modele dans la direction de la roulade, verrouillee pour toute sa duree play_char.visual_root.rotation.y = -dodge_dir.orthogonal().angle() func exit() -> void: play_char.is_dodging = false func physics_update(delta : float) -> void: applies() play_char.gravity_apply(delta) move(delta) dodge_timer -= delta if dodge_timer <= 0.0: end_dodge() func applies() -> void: #si le perso quitte le sol en roulant (ex: roulade vers un bord), on bascule vers InairState comme les autres etats au sol if !play_char.is_on_floor() and !play_char.is_on_wall(): if play_char.velocity.y < 0.0: transitioned.emit(self, "InairState") func move(_delta : float) -> void: if !play_char.is_on_floor(): return #falloff de vitesse : pleine vitesse par defaut, ou modele par dodge_speed_curve si assignee var ratio : float = 1.0 if dodge_speed_curve: ratio = dodge_speed_curve.sample(1.0 - (dodge_timer / dodge_duration_ref)) play_char.velocity.x = dodge_dir.x * play_char.dodge_speed * ratio play_char.velocity.z = dodge_dir.y * play_char.dodge_speed * ratio func end_dodge() -> void: #a la fin de la roulade, retour a l'etat approprie if !play_char.is_on_floor(): transitioned.emit(self, "InairState") elif Input.is_action_pressed(play_char.aim_cam_action): #AimState ne verra que "Dodge" comme etat precedent : on lui transmet l'origine crouch var aim : Node = play_char.state_machine.states.get("aimstate") if aim: aim.came_from_crouch = came_from_crouch transitioned.emit(self, "AimState") #le joueur a garde la visee enfoncee pendant la roulade elif came_from_crouch: transitioned.emit(self, "CrouchState") elif play_char.move_dir: transitioned.emit(self, play_char.walk_or_run) else: transitioned.emit(self, "IdleState") func get_hints() -> Variant: return null