Ball respawning not working properly

Godot Version

4.2

Question

Hi everyone!
I’m developing a clone of the breakout game and I have this problem.
I’m trying to implement ball respawning, when the ball goes off the screen (we lose a ball basically). When the ball is detected, I call up the ball repositioning function which reset the ball position to the center of the screen as when starting the game. I set a timer that keeps the ball still for a short time, after which it is launched towards the bricks. I don’t know why when I have to respawn, the ball is repositioned correctly until the timer expires, after which it disappears from the screen and is launched exactly from the point where leaved the screen. I don’t understand why the ball changes position when the timer expires.
This is the script code associated to the ball:

extends RigidBody2D

const SPEEDUP = 1.1
const MAXSPEED = 300
const INITIAL_SPEED = 200  
const DELAY = 2.0  
const VERTICAL_OFFSET = 150

@onready var ball_timer = $BallTimer
@onready var ball_notifier = $BallNotifier


var direction
var velocity
var viewport
var angle

func _ready():
	if not ball_notifier.is_connected("screen_exited", Callable(self, "_on_screen_exited")):
		ball_notifier.connect("screen_exited", Callable(self, "_on_screen_exited"))
	reset_ball_position()
	start_timer()

func reset_ball_position():
	randomize()
	viewport = get_viewport_rect()
	global_position = Vector2(viewport.size.x / 2, viewport.size.y - VERTICAL_OFFSET)
	set_linear_velocity(Vector2.ZERO)
	set_angular_velocity(0)
	apply_impulse(Vector2.ZERO)  
	apply_torque(0)  
	self.freeze = true

func start_timer():
	if not ball_timer.is_connected("timeout", Callable(self, "_on_timer_timeout")):
		ball_timer.connect("timeout", Callable(self, "_on_timer_timeout"))
	ball_timer.wait_time = DELAY
	ball_timer.one_shot = true
	ball_timer.start()

func _on_timer_timeout():
	self.freeze = false
	global_position = Vector2(viewport.size.x / 2, viewport.size.y - VERTICAL_OFFSET)
	#ball_timer.stop()
	angle = randf_range(-0.5, 0.5)
	direction = Vector2(angle, -1).normalized()
	velocity = direction * INITIAL_SPEED
	set_linear_velocity(velocity)

func _on_body_entered(body):
	if body.is_in_group("Brick"):
		body.queue_free()
	elif body.get_name() == "Paddle":
		var speed = get_linear_velocity().length()
		var paddle_center_x = body.global_position.x
		var collision_offset = global_position.x - paddle_center_x
		var normalized_offset = clamp(collision_offset / (body.get_node("Sprite2D").texture.get_size().x / 2), -0.6, 0.6)
		var direction = Vector2(normalized_offset, -1).normalized()
		var new_speed = min(speed * SPEEDUP, MAXSPEED)
		var velocity = direction * new_speed
		set_linear_velocity(velocity)
		
func _on_screen_exited():
	reset_ball_position()
	start_timer()

Any suggestion on how to solve this issue? Thanks in advance!

You may need to defer setting physics properties. It’s good practice to connect to signals using the signal directly like so, less Strings makes for less spelling errors.

if not ball_notififer.screen_exited.is_connected(_on_screen_exited):
    ball_notififer.screen_exited.connect(_on_screen_exited)

The ball could be triggering this screen exited signal during the physics thread, if you change certain properties during the physics thread it will overwrite your changes by the time it wraps up. We can add CONNECT_DEFERRED to our connection to wait to apply our function until the end of the frame

ball_notififer.screen_exited.connect(_on_screen_exited, CONNECT_DEFERRED)

I tried the solution you suggested, but it still gives me the same problem. I also tried connecting the notifier signal directly but it doesn’t work. I think I’ll try to use something else instead of the notifier because I have the impression that this is what causes this anomalous behavior