Ball collisions get wonky when it hits edges in my ping pong game

Godot Version

4.6Beta 2

Question

Hi

I’ve spent almost 2 weeks trying to solve a collision issue in my ping pong game, whenever the ball hits the paddle at the edges and the paddle moves, the balls collisions get messed up as shown in the video. I’ve tried everthing from different collision shapes to different ways to disable the collisions on impact, even to moving the ball’s global position on impact. But alas nothing worked, other than that, the collisions work fine when the ball hits the paddle’s face.

This is the ball code:

extends CharacterBody2D

var collided = false
const BALL_SPEED = 400
func _ready():
	velocity = Vector2(-0.5,0.2).normalized() * BALL_SPEED


func _physics_process(delta: float) -> void:
	var collision = move_and_collide(velocity * delta)
	if collision:
		var normal = collision.get_normal()
		#$AudioStreamPlayer.play()
		#print("ball collide")
		print(normal)
		velocity = velocity.bounce(normal)
		collided = true
		global_position += normal * 2.0  
		start_colliding()
		
func start_colliding():
	#print("starting collision")
	await get_tree().create_timer(0.2).timeout
	#print("ended")
	collided = false
	$CollisionShape2D.set_deferred("disabled", true)

and this is the paddle’s:

extends CharacterBody2D
var speed = 10
var accleration = 10
var is_rebounding = false
func _physics_process(delta: float) -> void:
	if is_rebounding == false:
		if Input.is_action_pressed("go_down"):
			velocity.y += speed * accleration
		if Input.is_action_pressed("go_up"):
			velocity.y -= speed * accleration
	move_and_slide()
	# Slide collision + normal + reboundation
	for i in get_slide_collision_count():
		var collision = get_slide_collision(i)
		var normal = collision.get_normal()
		print("I collided with ", collision.get_collider().name)
		#print(normal)
		if collision.get_collider().name == "TopWall":
			#print("top rebound")
			velocity = 300 * normal
			is_rebounding = true
			start_rebound()
		elif collision.get_collider().name == "BottomWall":
			#print("bot rebound")
			velocity = 300 * normal
			is_rebounding = true
			start_rebound()
func start_rebound():
	#print("starting rebound")
	await get_tree().create_timer(0.2).timeout
	#print("ended")
	is_rebounding = false

Try changing the CharacterBody2D.motion_mode to Floating

No luck, the same issue still occurs. The problem is that the ball collides multiple times when it hits the edges and the paddle is moving in its general direction, that’s why it jerks a bit, this is despite disabling the collisions on hit. Is there a way to disable collisions on the same tick as the collision?

I’m sure there is a way, but I think it would require reworking the engine itself. I’ve tried doing that but the engine seems to always defer the collision toggling to the next frame.

Maybe instead you can make the ball also exist on, say, layer 3 and the paddle can have a specialized top and bottom collision area to handle those circumstances.

Or you can try handling the situation where the normal vector is in a bad quadrant, to do something else to the ball.

I personally wouldn’t use CharacterBody2D for the ball myself , as you are then relying on move and slide which is going to try and do a lot of things you dont want it to, and that you have no control over.

I would just use a standard Area2d myself and use basic movement code, have three separate paddle ‘areas’ for detection of the ball (Top, Middle Bottom)and then use a reflection angle for the ball movement. When the ball hits it reflects the angle and direction depending on which part of the paddle it hits.

I doubt you will ever get it working properly with Move and Slide for the ball.

In your ball script, I suggest using the collision’s get_remainder().length to apply some of the bounce velocity in the same frame–see KinematicCollision2D — Godot Engine (stable) documentation in English. Consider a while loop to handle multiple collisions – there’s an example for this in comments of a related page: tutorials/physics/using_character_body_2d · godotengine/godot-docs-user-notes · Discussion #44 · GitHub

Also (and this may sound weird/silly) make sure your ball is above the paddle in the scene tree so that it’s physics process runs first (or write some code to verify which is running first) in case that makes a difference.