The Character Enters In Stunned Mode Two Times, it applies the knocback efect, lately

Godot Version

4.2.2

Question

Hi, everyone, i need some help, you see, im trying to add to my game a knockback effect, like those you see in some old games, like megaman, i already posted a question about the same proyect, but I ran into another problem, the character detects the knockback two times, so what happens is that I can crash with the enemy, while I walk, he throws me back, but if I press jump, the throwing effect is applied again, this also happens if for example the enemy walks towards me, he throws me, but if I press walk, he throws me again., i dont know if is because the states of the state machine or something, like it detects, the same colision for all the states, i tried to lock it using a global boolean variable to lock this, but it dont work, this is the code of the state machine:

class_name CharacterStateMachine
extends Node

@export var rising_gravity : int = 15
@export var fast_falling_gravity : int = 20
@export var _character : CharacterBody2D
@export var current_state : State
var _states : Array[State]


func _ready():
	for child in get_children():
		if (child is State):
			_states.append(child)
			child._character = _character
		else:
			push_warning("Child " + child.name + "is not in State for this Character")
			
			
func _physics_process(delta):
	if(current_state.next_state != null):
		switch_states(current_state.next_state)
	current_state.state_process(delta)

func check_if_can_move():
	return current_state.can_move

func switch_states(new_state : State):
	if(current_state != null):
			current_state.on_exit()
			current_state.next_state = null
	current_state = new_state
	current_state.on_enter_state()



	
func check_if_can_jump():
	return current_state.can_jump
	
func check_if_is_stunned():
	return current_state.can_be_stunned

func apply_gravity():
	if(current_state.apply_gravity):
		if(!_character.is_on_floor()):
			_character.velocity.y += rising_gravity
		if(_character.velocity.y > 0):
			_character.velocity.y += fast_falling_gravity
	_character.move_and_slide()

func check_if_can_be_stunned():
	return current_state.can_be_stunned

func _input(_event : InputEvent):
	current_state.state_input(_event)

and this for example is the air state, where it detects the colision two times:

class_name AirState
extends State


@onready var lurker_enemy = get_tree().get_first_node_in_group("Enemies")
@export var brax_actions_animation_player : AnimationPlayer
@export var brax_state_machine_functions : CharacterStateMachine
@export var brax_sprite : Sprite2D
@export var idle_state : State
@export var walking_state : State
@export var attack_state : State
@export var stunned_state : State

	

func state_process(delta):
	_apply_state_gravity()
	_movement_mid_air()
	_when_on_floor_after_fall()
	
	
func state_input(_event : InputEvent):
	if (_character.velocity.y < 0 and _event.is_action_released("JUMP")):
		_character.velocity.y *= 0.5
	
	elif _event.is_action_pressed("NORMAL_ATTACK"):
		_attack()
	

func _apply_state_gravity():
	brax_state_machine_functions.apply_gravity()
	

func _when_on_floor_after_fall():
	if _character.is_on_floor():
		if _character.velocity == Vector2.ZERO:
			next_state = idle_state
		elif Input.is_action_pressed("RIGHT"):
			next_state = walking_state
		elif Input.is_action_pressed("LEFT"):
			next_state = walking_state
	

func _attack():
	brax_actions_animation_player.play("air_attack")
	next_state = attack_state
	

func _movement_mid_air():
	if brax_state_machine_functions.check_if_can_move():
		if Input.is_action_pressed("RIGHT"):
			brax_sprite.flip_h = false
			_character.velocity.x = mid_air_speed
		elif Input.is_action_pressed("LEFT"):
			brax_sprite.flip_h = true
			_character.velocity.x = -mid_air_speed
		elif Input.is_action_just_released("RIGHT"):
			_character.velocity.x = 0
		elif Input.is_action_just_released("LEFT"):
			_character.velocity.x = 0


func _on_getting_hit_body_entered(body):
	if body == lurker_enemy:
		next_state = stunned_state


func _on_getting_hit_body_exited(body):
	if body == lurker_enemy:
		can_be_stunned = false

and this one is the walk state:

class_name WalkingState
extends State




#Enemigos que seran detectados por el jugador
@onready var lurker_enemy = get_tree().get_first_node_in_group("Enemies")

@export var brax_state_machine_functions : CharacterStateMachine
@export var brax_sprite : Sprite2D


#Estados Cambio
@export var idle_state : State
@export var air_state : State
@export var dash_state : State
@export var attack_state : State
@export var stunned_state : State

@export var brax_jump_sound_effect : AudioStreamPlayer2D
@export var brax_actions_animation_player : AnimationPlayer



func state_process(delta):
	_apply_state_gravity()
	_walk()
	_stop_walk()
	_after_falling_of_a_platform()
	_attack_while_walking()


func state_input(_event : InputEvent):
	if (_event.is_action_pressed("JUMP") and brax_state_machine_functions.check_if_can_jump()):
		_jump()
	
	if (Input.is_action_pressed("RIGHT") and _event.is_action_pressed("DASH")):
		next_state = dash_state
	
	if (Input.is_action_pressed("LEFT") and _event.is_action_pressed("DASH")):
		next_state = dash_state
	
	
func _walk():
	if brax_state_machine_functions.check_if_can_move():
		if Input.is_action_pressed("RIGHT"):
			brax_sprite.flip_h = false
			_character.velocity.x = walk_speed
		if Input.is_action_pressed("LEFT"):
			brax_sprite.flip_h = true
			_character.velocity.x = -walk_speed
		
		
func _stop_walk():
	if (Input.is_action_just_released("RIGHT") and not _character.velocity.x < 0):
		_character.velocity = Vector2.ZERO
	elif (Input.is_action_just_released("LEFT") and not _character.velocity.y > 0):
		_character.velocity = Vector2.ZERO
	
	elif _character.velocity == Vector2.ZERO:
		next_state = idle_state
	
	
func _apply_state_gravity():
	brax_state_machine_functions.apply_gravity()
	

func _after_falling_of_a_platform():
	if _character.velocity.y > 0 :
		next_state = air_state
		
		
func _attack_while_walking():
	if Input.is_action_just_pressed("NORMAL_ATTACK"): #Detener el movimiento mientras brax ataca al moverse
		_character.velocity.x = 0
		next_state = attack_state
	
	
func _jump():
	brax_jump_sound_effect.play()
	_character.velocity.y = base_jump_height
	next_state = air_state

func _on_getting_hit_body_entered(body):
	if body == lurker_enemy:
		next_state = stunned_state


func _on_getting_hit_body_exited(body):
	if body == lurker_enemy:
		next_state = idle_state

i would appreciate the help, seriously, thanks

Shouldn’t this return current_state.stunned_state?

Maybe I am missunderstanding this func, it seems odd to have two func that return the same thing.

2 Likes

Yeah, you see that function was to detect if the can be stunned variable was true, then the state is changed to stunned, but, yeah that din´t worked, so i added differents area2d for every state on the character, that way, i can disable and enable the area2d when needed, i dont know if that is the best way, but it worked