Modifying RigidBody2D positions after Out of Bounds

Godot Version

4.2.2 - Linux


I’m making a Croquet-style game, and when a ball passes out of bounds, I want to reset its position to be in-bounds again, at a point determined by where it exited the play area. I want to reset its velocity to 0, so it can act properly in the time between turns.

I know RigidBody2Ds are designed to take physics inputs instead of being directly manipulated, and most of the stuff I was finding for resetting positions was from 3.x, or involved retaining momentum.

My current solution is this, which is called at the end of each turn:

func _handle_oob(): 
	if not out_of_bounds:
		print("Ball ", ball_id, " not OoB!")
		return # catch anything that calls this by error

	var replace_ball_at = Vector2()
	# This is where the code figures out where to put the ball again
	# Omitted in this post for length

	freeze = true
	global_position = replace_ball_at
	set_deferred("freeze", false)
	out_of_bounds = false

It causes the ball to flash at the place where it should go for a frame, and then return to its out-of-bounds position. I can continue to apply forces to it, and it behaves properly, aside from being out of bounds.

How can I reposition it consistently?

Keep track of where the ball was on the last frame. When it goes out of bounds, the place to put the ball will be somewhere along the line formed between its prior position and its current position.

Calculate the intersection of that line with the edge of the playing field (see Geometry2D — Godot Engine (stable) documentation in English), and that is where you need to place the ball.

I have all that calculated, I just clipped out that code since a handful of position comparisons aren’t really related to my issue. I get the same issue no matter where I try to place it. My issue is that the ball goes where it’s supposed to for a single frame, then goes back to its out of bounds position

Don’t modify the transform of a rigid body directly as it will cause issues. Use RigidBody2D._integrate_forces() and modify its state parameter instead.

I don’t use RigidBody in my games, so I’m going to leave that to someone else.