Enemy respawn not following what the timers are set for

v4.3.stable.official [77dcf97d8]

New to coding and I’m having an odd bug where once my enemy respawns the ray cast timer gets overridden for some reason. I’ve tried everything that I could think of. I started off just trying to do a simple .stop() for all the animation and then starting them up again, but that didn’t work. after that i tried making separate post respawn timers to see if that would work, which it didn’t. I’ve also noticed that while it wont be the correct timers on respawn it will be the same timing. My player has a restart_level function so you can see that on death it resets back to what it’s supposed to be.

Video of bug


Code:

extends CharacterBody2D

var health_amount: int = 100
var is_dead: bool = false
var spawn_position: Vector2
var is_damaging: bool = false

@onready var respawn_timer: Timer = $respawn_timer
@onready var hurt_box = $hurt_box
@onready var hit_box = $hitbox
@onready var player = get_tree().get_first_node_in_group("Player")
@onready var damage_timeout = $damage_timeout
@onready var damage_ind = $damage_ind
@onready var sun_beam: RayCast2D = $sun_beam
@onready var sun_beam_timer: Timer = $sun_beam_timer
@onready var damage_tick_timer: Timer = $damage_tick_timer
@onready var respawn_sun_beam_timer: Timer = $respawn_sun_beam_timer
@onready var respawn_damage_tick_timer: Timer = $respawn_damage_tick_timer

func _ready():
	health_amount = 100
	spawn_position = global_position
	$model.play("sunflower_walk")
	damage_ind.visible = false
	
	hurt_box.visible = true
	hurt_box.monitoring = true
	hit_box.visible = true 
	hit_box.disabled = false
	
	sun_beam.enabled = false
	sun_beam_timer.wait_time = 2
	sun_beam_timer.one_shot = false
	sun_beam_timer.start()

	damage_tick_timer.wait_time = 0.02
	damage_tick_timer.one_shot = false  

	respawn_damage_tick_timer.wait_time = 0.02 
	respawn_damage_tick_timer.one_shot = false
	
	respawn_sun_beam_timer.wait_time = 4  
	respawn_sun_beam_timer.one_shot = false

func _physics_process(delta):
	aim()

func aim():
	sun_beam.target_position = player.position - global_position
	if sun_beam.is_colliding() and sun_beam.get_collider() == player and is_damaging:
		if damage_tick_timer.is_stopped():
			damage_tick_timer.start()

func _on_damage_tick_timer_timeout():
	if is_dead:
			return
	
	if sun_beam.is_colliding() and sun_beam.get_collider() == player and is_damaging:
		player.take_damage(1)
		damage_tick_timer.start()

func _on_sun_beam_timer_timeout():
	is_damaging = !is_damaging
	sun_beam.enabled = is_damaging
	
	if is_damaging:
		sun_beam_timer.wait_time = 2
	else:
		sun_beam_timer.wait_time = 2
	
	sun_beam_timer.start()

func _on_hurt_box_area_entered(area: Area2D) -> void:
	if area.get_parent().has_method("Get_damage_amount"):
		var node = area.get_parent() as Node
		damage_ind.visible = true
		damage_ind.text = str(node.damage_amount)
		damage_timeout.start()
		health_amount -= node.damage_amount
		
	if health_amount <= 0:
		die()

func _on_damage_timeout_timeout() -> void:
	damage_ind.hide()

func _on_respawn_timer_timeout():
	health_amount = 100
	is_dead = false
	visible = true
	position = spawn_position

	hurt_box.visible = true
	hurt_box.monitoring = true
	hit_box.visible = true
	hit_box.disabled = false

	is_damaging = false
	sun_beam.enabled = false

	respawn_damage_tick_timer.stop()
	respawn_sun_beam_timer.stop()
	sun_beam_timer.stop()

	respawn_damage_tick_timer.wait_time = 0.02
	respawn_sun_beam_timer.wait_time = 4
	sun_beam_timer.wait_time = 2

	respawn_damage_tick_timer.one_shot = false
	respawn_sun_beam_timer.one_shot = false
	sun_beam_timer.one_shot = true

	respawn_damage_tick_timer.start()
	respawn_sun_beam_timer.start()
	sun_beam_timer.start()

	is_damaging = true
	sun_beam.enabled = true

	print("Respawn completed and timers reset.")
	print("Damage Tick Timer Wait Time: ", respawn_damage_tick_timer.wait_time)
	print("Sun Beam Timer Wait Time: ", respawn_sun_beam_timer.wait_time)
	print("Sun Beam Timer Idle Time: ", sun_beam_timer.wait_time)
	print("Sun Beam Enabled: ", sun_beam.enabled)
	print("Is Damaging: ", is_damaging)

func die():
	is_dead = true
	visible = false    
	health_amount = 0
	respawn_timer.start(1)
	sun_beam.enabled = false
	call_deferred("disable_collision_shapes")
	is_damaging = false
	respawn_damage_tick_timer.stop()
	respawn_sun_beam_timer.stop()
	toggle_damage_mode(false)
	
func toggle_damage_mode(enable: bool):
	is_damaging = enable
	sun_beam.enabled = enable
	
	if enable:
		respawn_damage_tick_timer.start(0.02)
	else:
		respawn_damage_tick_timer.stop()

func disable_collision_shapes():
	hurt_box.visible = false
	hurt_box.monitoring = false
	
func _on_respawn_sun_beam_timer_timeout():
	is_damaging = !is_damaging
	sun_beam.enabled = is_damaging

	if is_damaging:
		respawn_damage_tick_timer.stop()
		respawn_damage_tick_timer.start(0.02)
		respawn_sun_beam_timer.start(4)
	else:
		respawn_damage_tick_timer.stop()
		respawn_sun_beam_timer.start(2)

	if is_damaging:
		respawn_damage_tick_timer.stop()
		respawn_damage_tick_timer.start(0.02)
		respawn_sun_beam_timer.start(4)
	else:
		respawn_damage_tick_timer.stop()
		respawn_sun_beam_timer.start(2)

I figured it out! I had to add in
sun_beam_timer.connect(“timeout”, Callable(self, “_on_sun_beam_timer_timeout”))
damage_tick_timer.connect(“timeout”, Callable(self, “_on_damage_tick_timer_timeout”))

into the onready

1 Like

Just a small heads-up, but in 4.3 there’s a less verbose way to bind to signals. Like this:

some_signal.connect(some_function.bind())