How can I give the player two chances to parry before triggering cooldown to make missed parries less punishing?

Godot Version

4.2.1

Question

I want to make my parry code a little more refined and give the player some leeway in case they miss the parry.

Currently it’s can be kind of tough to gauge the enemy hurtbox distance which can result in missing a parry and triggering the cooldown (and ends up hurting the player if the enemy has a quick follow up attack)

And I’d like for the player to have some “chance to recover”.
the image i have in my head is that the player has “2 chances” to parry before triggering the cooldown so that if they guess wrong on the enemy attack timing or miss gauge the distance they aren’t punished too roughly

parry code:

extends Player_State


@onready var parry_timer = $Parry_timer #0.25 sec window for parry
@onready var cooldown_timer = $Parry_CD_timer #0.5 sec CD

@export var ground_state : Player_State
@export var air_state : Player_State

func on_enter(): # start parry and set advance expression (animation)
	parry_timer.start() #the duration of the parry
	character.is_parrying = true 

func on_exit(): #set advance expression to exit the state 
	character.is_parrying = false

func _on_parry_timer_timeout(): #if the parry is unsuccessful the cooldown is triggered and prevents the player from retriggering the parry
	if !character.successful_parry: #successful parry var is triggered elsewhere
		cooldown_timer.start()
	character.successful_parry = false

#state transitions
	if character.is_on_floor():
		next_state = ground_state
	if !character.is_on_floor():
		next_state = air_state

any and all help is appreciated

how are you calling the

func on_enter():

is it a keyboard input? if so i would use

func _input(event)

for a more complete guess:

extends Node3D

@onready var parry_timer = $Parry_timer as Timer #0.25 sec window for parry
@onready var cooldown_timer = $Parry_CD_timer as Timer #0.5 sec CD

func _input(event: InputEvent) -> void:
	
	if Input.is_action_just_pressed("parry button"):
		if cooldown_timer.is_stopped(): #allow parrying only if the cooldown timer isn't active
			if parry_timer.is_stopped():
				parry_timer.start()
			
			print("complete parry action") #replace with whatever
			
func _on_parry_timer_timeout() -> void:
	cooldown_timer.start()
	parry_timer.stop() #must manually stop timers for the way i have coded the script

func _on_parry_cd_timer_timeout() -> void:
	cooldown_timer.stop() #must manually stop timers for the way i have coded the script

hope this was useful

how are you calling the: “func on_enter():”

on_enter() is a function that is a part of my state machine and is called whenever the player enters the state. for example if player is on the ground and presses the parry button then all code in the on_enter() function will be triggered once (kind of like _ready() but everytime the player enters the state)

I don’t quite see how this is different from my code. (I am a beginner so I might just be dumb)

What happens in my code is:

  • Player presses parry button and enters parry state (is handled in another state)
  • on_enter() triggers and starts timer as well as advance expression (used for animationtree)

(the successful parry is handled in the script where the player takes damage)

  • on timeout if parry has failed the cooldown starts and transitions to the appropriate state

I can’t see in the code how it handles giving the player “a second chance”

my script allows for the player to parry as many times as you can hit the key in a 0.25 second span, however now that you mention that this script uses a state machine I kind of understand what you’re trying to do.

also, i don’t understand where you got this "Player_State, as it is not a default Godot node as far as i know


by 2 chances, does that include a specified amount of time that is available for you to attempt a second parry? how long does the parry take?(I think 0.25s according to your code)

Al I’m saying is that I’m slightly confused by what you are trying to achieve, Maby I didn’t read it correctly, but if you know exactly what you want it shouldn’t be hard to write down inputs and outputs, then implement that logic in code.

good luck.