Gravity is not applying to a Boss Enemy, when it's in a certain state

Godot Version

4.2.2

Question

Hello,
I’ve been following the below tutorial and created a boss enemy for my game.

The boss_enemy uses a Finite State Machine to switch between states.
I made slight modifications to fit my game. (Added gravity, additional states, etc.)

As per the tutorial, the _physics_process is disabled initially. And is enabled on whichever states that require it.
In the tutorial and my original code, _physics_process is enabled only in the “Follow” state. It is disabled in all other states.

Afterward, I introduced 2 new states.

  • Death_Fall (_physics_process enabled)
  • Death_Collapse

When the boss_enemy dies, the states change in the following order.
→ Death_Fall (Till is_on_floor == true, has gravity) → Death-Collapse (No gravity)


The issue I’m facing is as follows.

When moving from a state where _physics_process is disabled (Ex: “RangedAttack” state), the gravity is applied after moving to the “Death_Fall” state without any issue.

But when the current_state is the “Follow” state (where _physics_process is enabled), and when moving to the “Death_Fall” state, the gravity is not applied.

Pasted the relevant code snippets below.

Scene Tree of the Boss_Enemy node:

Boss Enemy Main Script (Only included the code snippets relevant to this question):

extends CharacterBody2D

@onready var player = get_tree().get_nodes_in_group(Gamemanager.GROUP_PLAYER)[0].marker_2d
@onready var sprite = $Sprite2D
@onready var finite_state_machine = $FiniteStateMachine
@onready var animation_player_damaged = $AnimationPlayer_Damaged
@onready var progress_bar = $ProgressBar
@onready var progress_bar_timer = $ProgressBar_Timer
@onready var stagger_timer = $StaggerTimer
@onready var audio_stream_player_2d = $AudioStreamPlayer2D
@onready var hitbox_collision_shape_2d = $Hitbox/CollisionShape2D
@onready var laser_collision_shape_2d = $Pivot/Area2D/CollisionShape2D
@onready var hitbox = $Hitbox

@export var death_fall_state: State
@export var death_collapse_state: State

var direction: Vector2
var speed: float = 60

var _gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
var _dying: bool = false
var is_staggered: bool = false
var invincible: bool = false
var can_move: bool = true

var points: int = 1000
var enemy_health: int = 2

func _ready():
	set_physics_process(false)
	progress_bar.max_value = enemy_health

func _process(delta):
	progress_bar.value = enemy_health
	direction = player.global_position - global_position	
	
	if direction.x < 10:
		sprite.flip_h = true
	else:
		sprite.flip_h = false

func _physics_process(delta):
	if finite_state_machine.current_state == death_fall_state or finite_state_machine.current_state == death_collapse_state:
		velocity.x = 0
		velocity.y += _gravity * delta
		move_and_slide()
	else:
		if position.distance_to(player.position) > 100:
			velocity = direction.normalized() * speed
			move_and_collide(velocity * delta)
		
		

func get_damaged_by_bullet():
	
	enemy_health -= 1
	if enemy_health <= 0:
		die()
	else:
		return

func die():
	if _dying == true:
		return
	_dying = true
	Signalmanager.on_enemy_hit.emit(points)
	finite_state_machine.change_state("Death_Fall")


func _on_hitbox_area_entered(area):
	if invincible == true:
		return
	else:
		invincible = true
		progress_bar.visible = true
		is_staggered = true
		progress_bar_timer.start()
		stagger_timer.start()
		
		animation_player_damaged.play("damaged")

		if area.is_in_group("player_bullet"):
			get_damaged_by_bullet()


Finite State Machine script (Attached to the FiniteStateMachine node) :

extends Node2D


var current_state: State
var previous_state: State

func _ready():
	current_state = get_child(0) as State
	previous_state = current_state
	current_state.enter()

func change_state(state):
	current_state = find_child(state) as State
	current_state.enter()
	
	previous_state.exit()
	previous_state = current_state

State.gd:

extends Node
class_name State

@onready var player = get_tree().get_nodes_in_group(Gamemanager.GROUP_PLAYER)[0].player_hitbox
@onready var animation_player = owner.find_child("AnimationPlayer")
@onready var debug = owner.find_child("Label")
@onready var debug2 = owner.find_child("Label2")

func _ready():
	set_physics_process(false)
	
func enter():
	set_physics_process(true)
	
func exit():
	set_physics_process(false)
	
func transition():
	pass
	
func _physics_process(delta):
	transition()
	debug.text = name
	debug2.text = "Player position :" + str(player.global_position)

Follow.gd (Script for the “Follow” state. Child of the FiniteStateMachine node. Extended from State.gd script) :

extends State
@onready var boss_enemy_level_01 = $"../.."

func enter():
	super.enter()
	owner.set_physics_process(true)
	animation_player.play("idle")

func exit():
	super.exit()
	owner.set_physics_process(false)

func transition():
	var distance = owner.direction.length()
	
	if boss_enemy_level_01._dying == true:
		owner.set_physics_process(true)
		get_parent().change_state("Death_Fall")
	else:
		if distance < 30:
			get_parent().change_state("MeleeAttack")
		elif distance > 130:
			var chance = randi() % 2
			match chance:
				0:
					get_parent().change_state("RangedAttack")
				1:
					get_parent().change_state("LaserBeam")

Death_Fall.gd (Script for the “Death_Fall” state. Child of the FiniteStateMachine node. Extended from State.gd script) :

extends State
@onready var boss_enemy_level_01 = $"../.."

func enter():
	super.enter()
	owner.set_physics_process(true)
	animation_player.play("death_fall")

func exit():
	super.exit()
	owner.set_physics_process(false)

func transition():
	if boss_enemy_level_01.is_on_floor():
		get_parent().change_state("Death_Collapse")

Any help on this would be much appreciated.