Pong - Ball is being dragged when paddle moves on the same direction

Godot Version

4.4.1

Question

Hi all,

I’m currently making with a simple pong clone using Godot. While the game is mostly functional, I’ve getting this behavior that is annoying.

The issue is whenever the paddle and the ball are moving in the same direction (both moving up or down) and the paddle is faster than the ball, when the ball hits the paddl it seems to “stick” to or get dragged along with it for a few frames before bouncing off. This doesn’t happen when the paddle is stationary or moving in the opposite direction — in those cases, the bounce feels clean.

I’m not necessarily looking for a fix (yet), but more interested in understanding why this happens. I guess I could “brute force” some logic so that never happens in those specific cases but I don’t want to over-engineer the solution. Can some maybe explain this to me?

Some context:

  • I’m using StaticArea for the paddle and CharacterBody2D for the ball because I assumed I can have more fine control of the objects using code, RigidBody2D felt like overkill for a simple game, (and I want to learn also)
  • I’m software dev already but completely new to game dev, so physics is all greek to me
    I suspect this might be due to how the physics engine resolves overlapping bodies or how it calculates collision normals when both objects are moving. But I’d love to hear from more experienced devs. is this expected behavior?

Thanks in advance for any insights!

Note: the paddle and the ball are in different collision layers, and paddle only have the mask layer with the walls.

ball.gd

extends CharacterBody2D

var collision_data : KinematicCollision2D

func _ready():
	var x = randf_range(0, TAU)
	var y = randf_range(0, TAU)
	velocity = Vector2(x,y) * 200

func _physics_process(delta):
	collision_data = move_and_collide(velocity * delta)
	
	if collision_data:
		velocity = velocity.bounce(collision_data.get_normal())

paddle.gd

extends StaticBody2D

@export var max_speed = 600
@export var accel = 800
@export var friction = 600

var input = Vector2.ZERO
var velocity = Vector2.ZERO

func _physics_process(delta: float) -> void:
	player_movement(delta)
	velocity.x = 0
	
func get_input():
	input.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
	return input.normalized()
	
func player_movement(delta):
	input = get_input()
	
	if input == Vector2.ZERO:
		if velocity.length() > (friction * delta):
			velocity -= velocity.normalized() * (friction * delta)
		else:
			velocity = Vector2.ZERO
	else:
		velocity += (input * accel * delta)
		velocity = velocity.limit_length(max_speed)
			
	move_and_collide(velocity * delta)

output

My first guess it has nothing to do with your code, and instead is your scene tree. If your ball is a child of your paddle, its location is going to be relative to that of its parent (the paddle). If this is the case, make the ball a child of your game instead of the paddle.

I wish this was the solution but it’s not, the paddle, the walls and the ball are all in the same level.
After I posted the question I tried other things, for example changing the paddle types to character2d, changing the collision from Grounded to Floating, even increasing the priority (only made the game slower)
I guess similar questions have been asked already in this forum, I found one that seems to have somewhat similar problem (balls colliding with a paddle)

Anyway, I digress, the only suspicion I have is that when the ball collides with the paddle and both are moving, the objects overlaps so on every frame the direction of the ball is calculated until they stop overlapping, instead of one single collision calculation as it happens when the paddle is not moving.

I have no idea to test this hypothesis though, even less how to fix if it was the case.

1 Like

Ok, well looking at your code now, I see a couple things. My bad for not doing that this morning.

1.) Your ball is a CharacterBody2D. It should be a Rigidbody2D. It’s literally something that is acted upon by physics.
2.) Your paddle should be a CharacterBody2D. A StaticBody2D says in the documentation that it teleports when moved. This is probably contributing to the weirdness you are seeing.
3.) You should try using move_and_slide() not move_and_collide() to move your paddle. If that doesn’t work, then move on to the latter, but move_and_slide() handles collisions and redirections for CharacterBody2D objects.. (Not using it for your ball may also be causing weirdness - I dunno. But again, it shouldn’t be one and your paddle should be.)

Basically, if an object is receiving player input, it should be a ChracterBody2D. If you want an object to react to physics with other objects and move on its own, it should be a RigidBody2D.

Hey, just wanted to give an update and say thanks!

After thinking it through (and banging my head against the wall a bit more :sweat_smile:), I decided to go with RigidBody2D for the ball and move forward. It really does make the bouncing and physics feel right with way less work, and I realized that in this case, trying to do it all manually with CharacterBody2D was slowing me down more than it was helping me learn. The bouncyness still doesn’t feel right but I guess I can adjust some parameters like damp and gravity. Sometimes its jusr better to use the builtin tools godot gives instead of fighting it for the sake of control. I still couldnt understand what was exactly happening but i guess i can come back to it in the future when/if I have more time and experience

Really appreciate the help, thanks alot. Awesome community. :raising_hands:

Take a look at physics materials. You can use that to get the bounciness you’re looking for.

That’s always the case. Anything Godot is doing for you - let it. The learning can come in when it’s not doing something you really want. Then you’ll already have an idea of how things are done and can play around with some knowledge going in. That’s my recommendation anyway.

1 Like

Good switch to RigidBody2D, for reference the issue with a CharacterBody2D was probably in “Grounded” mode used for platformer side-view games; so it would treat the paddle as a moving platform and snap to it, you could fix this by setting them to “Floating” mode usually for top-down games, or reducing it’s floor layers.

2 Likes