How do I fix collision errors at the edge of my paddle?

Godot Version

Godot 4.2.2

Question

So I’m working on a Pong game and I recently encountered this error where once the ball hits the edge of the paddle (or somewhere close to it), some weird things happen. Here’s a video of the main problem:


Another thing that happens in this collision is the ball changing its direction/angle and moving more slanted or even going in an up or down movement. How do I fix this?

Any help would be appreciated, Thanks in advance :smiley:

Unique names should not be used to get siblings or parents. Shouldn’t Dust be a child of ball? You could set it’s “top level” property On so it behaves as if it was a child of root.

I’m quite confused though, what unique names?

But collision-wise, I think the problem is the fact that there isn’t much position or angle happening when the collision occurs.

Here’s the script that’s supposed to deal with the edge, apparently the engine is saying it has no effect, What I’m I doing wrong?

if collision.get_collider().name == "Paddle":
		if collision.get_normal() != Vector2.UP:
	 # side of paddle
			velocity.bounce(collision.get_normal()) * speed #(Line 40 (STANDALONE_EXPRESSION):Standalone expression (the line has no effect)).

% is the unique name identifier. %Dust2 isn’t a chlid of Ball, so the script cannot find it via Unique name, $../Dust2 is the correct path, but it’s bad practice to search for parent nodes, makes for very rigid scenes that break down at slight scene changes.

It manages to find %Dust by coicidence/bug, do not trust that to work either

1 Like

bounce returns a vector, it does not modify the vector. need to set velocity to apply the modification

velocity = velocity.bounce(collision.get_normal()) * speed
2 Likes

I never realized the hierarchy of the nodes affected the unique names in any way, I’ll change it.

Oh apologies, I cannot see the entire line. move_and_collide can return nothing, if it does not collide. Can you paste your _physics_process function, I am willing to bet you are move_and_collideing the ball twice, the second time it is not colliding so using get_position() on that function gives you the error.

func _physics_process(delta: float) -> void:
	var collision = move_and_collide(velocity * delta * speed) 

	if not collision:
		return

	if collision.get_collider().name == "Paddle":
		if collision.get_normal() != Vector2.UP:
	 # side of paddle
			velocity = velocity.bounce(collision.get_normal()) * speed
	if collision.get_collider().name == "Paddle" and %Timer.is_stopped():
		score += 1
		label.text = str(score)
		%Timer.start()
		speed += 10
		print(speed)
		hit_sound_2.play()
		hit_sound.play()
	if collision.get_collider().name == "Borders":
		hit_sound.play()

	if collision.get_collider().name == "DeathArea":
		pop_sound.play()
		game_over_sound.play()
		visible = false
		game_over_screen.visible = true
		get_tree().paused = true

Huh, where do you call SpawnDust?
So SpawnDust calls move_and_collide again, that’s what is moving the ball. You will need to pass SpawnDust the collision data instead of trying to use the function to generate new collision data

func Spawn_Dust():
	%Dust.global_position = move_and_collide(velocity).get_position()
	%Dust.emitting = true
	%Dust.restart()
	
func Spawn_Dust_2():
	%Dust2.global_position = move_and_collide(velocity).get_position()
	%Dust2.emitting = true
	%Dust2.restart()

But when I tried to add the collision variable in place of the move and collide, it threw an error saying that the variable (or in this case identifier) wasn’t declared in the function.

pass the variable as an argument

func Spawn_Dust(collision_point: Vector2) -> void:
	%Dust.global_position = collision_point
	%Dust.restart()

I still do not know where you call th Spawn_Dust function, I really think it should be in physics process so here’s an example in there

func _physics_process(delta: float) -> void:
	var collision = move_and_collide(velocity * delta * speed) 

	if not collision:
		return

	Spawn_Dust(collision.get_position())

I call the dust particles when it collides with the walls or paddle

Also I’m not sure where that (delta: float) → void and other ones came from in my script. I’ve removed so you don’t need it there anymore

Also for some reason my ball isn’t moving or responding at all anymore, I think it has something to do with the autoload I tried to add but removed earlier, what’s going on?

Those are the function arguments, it’s how functions can be given arbitrary data, in _physics_process it’s how the function knows the time between frames. It’s required and very useful.

I want you to add function arguments to Spawn_Dust and show where this function is called, meaning it won’t have func at the start, just Spawn_Dust()

You mean this?

if collision.get_collider().name == "Paddle" or "Borders" and %Dust.emitting == true:
		Spawn_Dust_2()
	else:
		Spawn_Dust()

Yup, that is the function call. if it has func at the start it is the function definition. After you add those function arguments back (delta: float and my requested collision_point: Vector2) you will have to call the function with an argument like so

var collider_name = collision.get_collider().name
# comparisons cannot just be `or "Borders` it doens't 
# know you want to compare the collider's name to "Borders"
if (collider_name == "Paddle" or collider_name == "Borders") and %Dust.emitting:
	Spawn_Dust_2(collision.get_position())
else:
	Spawn_Dust(collision.get_position())

Alright, I’ll try applying everything you just mentioned and see if it will work.

I also have to admit that I don’t really understand anything that’s going on here and I’m just following what you’re telling me to do :slightly_frowning_face:. So is there anywhere I can get better knowledge on stuff like this?

Same principle in python, replace def with func for gdscript

Actually a list of things GDScript does not do:

  1. Arbitrary arguments (*args)
  2. Positional only arguments(, /)
  3. Keyword arguments
  4. Keyword only arguments (*, x)
1 Like

My ball still isn’t moving still so I’m not even able to test and see if this works.

And also what about this line?

f collision.get_collider().name == "Paddle":
		if collision.get_normal() != Vector2.UP:
	 # side of paddle
			velocity = velocity.bounce(collision.get_normal()) * speed

Does it still do as functioned or there’s something I need to fix here? (the ball will move the same way when it hits the middle of the paddle when hitting the edge)

It probably speeds the ball up a tremendous amount, I would remove * speed.

I do not know what your script looks like now, could you post the entire Ball.gd? Sorry

If you do not have delta in your physics process, the whole thing will fail

func _physics_process(delta: float) -> void: