How to prevent RigidBody2Ds being pushed through StaticBody2Ds?

Godot Version

4.2.2

Question

Hello! So I have a moving wall (which is also a staticbody2d), a ball, and several static walls. The issue I am running into, is that when the moving wall happens to trap the ball between itself and a static wall, the ball will get pushed through the static wall.

The moving wall only lasts a few seconds, and moves rather slowly, so this issue does not naturally occur often, but can be intentionally done fairly easily. My attempted solution was to make the moveing wall break after 10 collisions with the ball. The collisions are tracked correctly, and the moving wall does break after 10 collisions, however, when it traps the ball, it doesn’t count it as multiple collisions it seems, as the collision counter does not increase after the last bounc the ball does before being trapped.

Is there a better way to do this? I was thinking of having the moving wall continuously check the position of the ball, and all other walls (by using a wall group) and making it so if the ball is within a certain distance and direction of the moving wall and any static wall, that the moving wall breaks. However, this seems overly complicated, and I’m sure there’s a better solution.

Any thoughts?

Here is the script for the wall for reference:

extends StaticBody2D

var speed = 600
var max_distance = 1800
var direction = Vector2.RIGHT
var distance_traveled = 0.0
var team = null

var times_hit = 0
var max_hits = 10
var line2d
var line_length = 20
var bottom
var top

# Called when the node enters the scene tree for the first time.
func _ready():
	bottom = $Bottom.position
	top = $Top.position
	
	# Initialize the Line2D node
	line2d = Line2D.new()
	line2d.default_color = Color.BLUE
	line2d.z_index = 1
	add_child(line2d)
	line2d.add_point(Vector2(bottom.x, bottom.y))  # Starting point


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
	var movement = direction * speed * delta
	position += movement
	distance_traveled += movement.length()
	
	if distance_traveled >= max_distance:
		queue_free()
	if times_hit >= max_hits:
		queue_free()

func add_line_segment():
	# Calculate the total distance from bottom to top
	var total_distance = bottom.y - top.y
	# Calculate the step distance for each hit
	var step_distance = total_distance / max_hits
	
	# Calculate the new point position based on times_hit
	var new_y = bottom.y - (step_distance * times_hit)
	var new_point = Vector2(bottom.x, new_y)
	
	# Add the new point to the Line2D
	line2d.add_point(new_point)



func _on_area_entered(area):
	if area.is_in_group("projectile"):
		times_hit += 1
		add_line_segment()
		if area.is_in_group("child_area"):
			area = area.get_parent()
			area.delete()
		if not area.is_in_group("no_despawn"):
			area.queue_free()
	
	if area.is_in_group("ball"):
		times_hit +=1
		add_line_segment()
	
	if area.is_in_group("outer_wall"):
		queue_free()

What if you track (via a script on the ball?) collisions it makes and report them via signal to the problem wall. The problem wall then has logic that checks who the collsion is with, how long ago it was, and analyzes if it is a problem and should back off?

That did it! A version of that at least. Made a timer on the wall, and had it start whenever the ball entered the area, and had it stop whenever the ball left the area. Set it to 0.1 seconds and it consistently queue_free()'s before the ball gets shoved through.

Thanks a ton!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.