From 042840309de4619d47ff5d148a0d4bc91c18a402 Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Sun, 27 Sep 2026 10:31:36 +0200 Subject: [PATCH] Add DodgeState --- .../InputManagementComponent.gd | 2 + game/player/PlayerCharacter.tscn | 4 + game/player/StateMachine/AimState.gd | 10 +++ game/player/StateMachine/DodgeState.gd | 76 +++++++++++++++++++ game/player/StateMachine/DodgeState.gd.uid | 1 + game/player/StateMachine/IdleState.gd | 3 + game/player/StateMachine/PlayerCharacter.gd | 16 +++- game/player/StateMachine/RunState.gd | 3 + game/player/StateMachine/WalkState.gd | 3 + 9 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 game/player/StateMachine/DodgeState.gd create mode 100644 game/player/StateMachine/DodgeState.gd.uid diff --git a/game/player/InputManagementComponent/InputManagementComponent.gd b/game/player/InputManagementComponent/InputManagementComponent.gd index c2eeba7..27dbbbc 100644 --- a/game/player/InputManagementComponent/InputManagementComponent.gd +++ b/game/player/InputManagementComponent/InputManagementComponent.gd @@ -12,6 +12,7 @@ class_name InputManagementComponent @export var move_right_action : StringName = "player_move_right" @export var run_action : StringName = "player_run" @export var jump_action : StringName = "player_jump" +@export var dodge_action : StringName = "player_dodge" @export_subgroup("Camera variables") @export var aim_cam_action : StringName = "player_aim_camera" @export var cam_zoom_in_action : StringName = "player_zoom_camera_in" @@ -36,6 +37,7 @@ func attribute_keybinds() -> void: play_char_ref.move_right_action = move_right_action play_char_ref.run_action = run_action play_char_ref.jump_action = jump_action + play_char_ref.dodge_action = dodge_action play_char_ref.aim_cam_action = aim_cam_action cam_holder_ref.aim_cam_action = aim_cam_action diff --git a/game/player/PlayerCharacter.tscn b/game/player/PlayerCharacter.tscn index 3b5fad4..dfa72e0 100644 --- a/game/player/PlayerCharacter.tscn +++ b/game/player/PlayerCharacter.tscn @@ -9,6 +9,7 @@ [ext_resource type="Script" uid="uid://dr5p8ygj25w6x" path="res://game/player/StateMachine/JumpState.gd" id="6_lwgph"] [ext_resource type="Script" uid="uid://dn5idrvu68k83" path="res://game/player/StateMachine/AimState.gd" id="7_kxr4l"] [ext_resource type="Script" uid="uid://dpcfffs3vt5co" path="res://game/player/StateMachine/RunState.gd" id="8_j4mf1"] +[ext_resource type="Script" uid="uid://bwojkp7yrwswt" path="res://game/player/StateMachine/DodgeState.gd" id="9_6abew"] [sub_resource type="Curve" id="Curve_kxr4l"] _limits = [0.0, 10.0, 0.0, 1.0] @@ -85,5 +86,8 @@ script = ExtResource("7_kxr4l") [node name="RunState" type="Node" parent="StateMachine" unique_id=1345421775] script = ExtResource("8_j4mf1") +[node name="DodgeState" type="Node" parent="StateMachine" unique_id=232179400] +script = ExtResource("9_6abew") + [node name="InputManagementComponent" type="Node" parent="." unique_id=1981951371] script = ExtResource("2_r5dqo") diff --git a/game/player/StateMachine/AimState.gd b/game/player/StateMachine/AimState.gd index b0a4bc1..1774cc4 100644 --- a/game/player/StateMachine/AimState.gd +++ b/game/player/StateMachine/AimState.gd @@ -23,6 +23,7 @@ var play_char : CharacterBody3D @export var aim_move_accel : float = 8.0 var auto_lock_blocked : bool = false #true apres un deverrouillage manuel, tant que la cible est encore au centre +var dodging_from_aim : bool = false #true quand on quitte Aim pour rouler, pour ne pas relacher la cible verrouillee func enter(play_char_ref : CharacterBody3D) -> void: play_char = play_char_ref @@ -34,6 +35,10 @@ func verifications() -> void: play_char.cam_holder.cam_aimed = true func exit() -> void: + if dodging_from_aim: + #on roule en visant : la camera et la cible verrouillee restent actives pendant la roulade + dodging_from_aim = false + return release_target() if play_char: play_char.cam_holder.cam_aimed = false @@ -51,6 +56,11 @@ func applies() -> bool: return false func input_management() -> bool: + if Input.is_action_just_pressed(play_char.dodge_action) and play_char.dodge_cooldown <= 0.0: + dodging_from_aim = true + transitioned.emit(self, "DodgeState") + return true + if !Input.is_action_pressed(aim_action): transitioned.emit(self, play_char.walk_or_run if play_char.move_dir else "IdleState") return true diff --git a/game/player/StateMachine/DodgeState.gd b/game/player/StateMachine/DodgeState.gd new file mode 100644 index 0000000..1611d4d --- /dev/null +++ b/game/player/StateMachine/DodgeState.gd @@ -0,0 +1,76 @@ +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 + +func enter(play_char_ref : CharacterBody3D) -> void: + play_char = play_char_ref + + 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): + transitioned.emit(self, "AimState") #le joueur a garde la visee enfoncee pendant la roulade + elif play_char.move_dir: + transitioned.emit(self, play_char.walk_or_run) + else: + transitioned.emit(self, "IdleState") diff --git a/game/player/StateMachine/DodgeState.gd.uid b/game/player/StateMachine/DodgeState.gd.uid new file mode 100644 index 0000000..79e2e69 --- /dev/null +++ b/game/player/StateMachine/DodgeState.gd.uid @@ -0,0 +1 @@ +uid://bwojkp7yrwswt diff --git a/game/player/StateMachine/IdleState.gd b/game/player/StateMachine/IdleState.gd index e05d1d0..fcf94f5 100644 --- a/game/player/StateMachine/IdleState.gd +++ b/game/player/StateMachine/IdleState.gd @@ -44,6 +44,9 @@ func applies() -> void: func input_management() -> void: #manage the state transitions depending on the actions inputs + if Input.is_action_just_pressed(play_char.dodge_action) and play_char.dodge_cooldown <= 0.0: + transitioned.emit(self, "DodgeState") + if Input.is_action_pressed(play_char.jump_action) if play_char.auto_jump else Input.is_action_just_pressed(play_char.jump_action): transitioned.emit(self, "JumpState") diff --git a/game/player/StateMachine/PlayerCharacter.gd b/game/player/StateMachine/PlayerCharacter.gd index 57cc279..c7e28cc 100644 --- a/game/player/StateMachine/PlayerCharacter.gd +++ b/game/player/StateMachine/PlayerCharacter.gd @@ -13,6 +13,7 @@ var last_frame_position : Vector3 var last_frame_velocity : Vector3 var was_on_floor : bool = false var walk_or_run : String = "WalkState" #keep in memory if play char was walking or running before being in the air +var is_dodging : bool = false #true while DodgeState is active ; hook this up to a hurtbox/i-frame check later @export_group("Walk variables") @export var walk_speed : float = 5.0 @@ -25,6 +26,12 @@ var walk_or_run : String = "WalkState" #keep in memory if play char was walking @export var run_deccel : float = 6.5 @export var continious_run : bool = false #if true, doesn't need to keep run button on to run +@export_group("Dodge variables") +@export var dodge_speed : float = 10.0 +@export var dodge_duration : float = 0.4 +@export var dodge_cooldown : float = 0.6 +var dodge_cooldown_ref : float + @export_group("Jump variables") @export var jump_height : float = 3.0 @export var jump_time_to_peak : float = 0.35 @@ -94,15 +101,17 @@ func _ready(): jump_cooldown_ref = jump_cooldown nb_jumps_in_air_allowed_ref = nb_jumps_in_air_allowed coyote_jump_cooldown_ref = coyote_jump_cooldown + dodge_cooldown_ref = dodge_cooldown #connect_footstep_audio_effect() func _process(delta: float): modify_model_orientation(delta) -func _physics_process(_delta : float): +func _physics_process(delta : float): update_run_toggle() modify_physics_properties() + tick_dodge_cooldown(delta) move_and_slide() @@ -137,6 +146,11 @@ func modify_physics_properties(): last_frame_position = position #get play char position every frame last_frame_velocity = velocity #get play char velocity every frame was_on_floor = !is_on_floor() #get if play char is on floor or not + if move_dir != Vector2.ZERO: last_input_dir = move_dir #memorize the last non-zero input direction, used as a dodge fallback + +func tick_dodge_cooldown(delta : float) -> void: + if dodge_cooldown > 0.0: + dodge_cooldown -= delta func gravity_apply(delta : float): #if play char goes up, apply jump gravity diff --git a/game/player/StateMachine/RunState.gd b/game/player/StateMachine/RunState.gd index ec866ab..59c630e 100644 --- a/game/player/StateMachine/RunState.gd +++ b/game/player/StateMachine/RunState.gd @@ -46,6 +46,9 @@ func applies() -> void: transitioned.emit(self, "JumpState") func input_management() -> void: + if Input.is_action_just_pressed(play_char.dodge_action) and play_char.dodge_cooldown <= 0.0: + transitioned.emit(self, "DodgeState") + if Input.is_action_pressed(play_char.jump_action) if play_char.auto_jump else Input.is_action_just_pressed(play_char.jump_action): transitioned.emit(self, "JumpState") diff --git a/game/player/StateMachine/WalkState.gd b/game/player/StateMachine/WalkState.gd index ea2a043..3cf1a9f 100644 --- a/game/player/StateMachine/WalkState.gd +++ b/game/player/StateMachine/WalkState.gd @@ -46,6 +46,9 @@ func applies() -> void: transitioned.emit(self, "JumpState") func input_management() -> void: + if Input.is_action_just_pressed(play_char.dodge_action) and play_char.dodge_cooldown <= 0.0: + transitioned.emit(self, "DodgeState") + if Input.is_action_pressed(play_char.jump_action) if play_char.auto_jump else Input.is_action_just_pressed(play_char.jump_action) : transitioned.emit(self, "JumpState")