How to fix the score changing twice due to Slight Collison when the ball leaves the paddle?

Godot Version

Godot 4.2

Question

So I’m working on a pong game as a way to get familiar with the engine, but I’ve ran into a problem when increasing my score. When the ball hits the paddle, the score increases but as it slightly still touches the paddle as it moves away from it, It still increases the score making the score go from 1 to 3 etc.

This could be fixed with something like a ‘wait until not colliding’ thing, but of course this isn’t Scratch and I’m not really sure how to implement such a thing in Godot. Can anyone help me out?

I need more information, show the codes

Alright, here it is (Credits to @Sven for giving me the code and @pennyloafers for helping me know what which one is which, I added the score counter and did some tweaks on my own)

extends CharacterBody2D

var speed = 500
var movement = Vector2(0, speed)
var score = 0
@onready var label = $"../Label"

func _physics_process(delta):
	# moves charbody and returns collided objects, borders or paddles
	var collision = move_and_collide(movement * delta)
		
	if collision:
		if collision.get_collider().name == "Paddle":
	  #reverses direction 
			speed = -speed
			score += 1
			label.text = str(score)
			# gets difference position  of paddle position and ball position.
			var diff = collision.get_collider().position.y - position.y
			# use difference to change up/down direction of ball movement.
			var new_movement = Vector2(-diff * 6, speed)
			# update movement 
			movement = new_movement
		elif collision.get_collider().name == "Borders":
	  # collision normal is the direction the border is facing. Bounce function just reflects the movement vector at an angle between the normal and movement.
			movement = movement.bounce(collision.get_normal())

Hmmm, add a timer and set the wait time to 0.5 secs and test it, if its works, decrease the wait time like set it to 0.1, wait, follow the steps

  1. Add a variable, “can_add_score = true”
  2. Start the timer
...
score += 1
can_add_score = false
$Timer.start()
...
  1. Connect the timer timeout and add this codes in that function:
can_add_score = true
  1. Test it.

I actually tried this solution but failed doing so, but maybe I could try this again through your approach.
I’ll test this and see if it works.

1 Like

It didn’t work, I think the problem now is that nothing actually happens when the variable is true or false. So I think an if/else condition should do the trick

1 Like

Try adding a state like ‘is_colliding’ and only increase the score of the state is not true.
Set the state to true when the collision happens and reset it to false when there is no collision.

At first you can nest this inside the if-statement and later re-factor it.

This seems like a great idea, But where and how would I apply it in my code?

Also I’m using a CharacterBody2d so I don’t have access to that function

Hi ZV1LLE,
I have expanded the code here so that it is at least functional. To make it useful for you, you may have to change it again. But it worked for me. My code is of course a little different, but I think you see what you need.
What are you actually planning to do with the scorekeeper for the ball?

extends CharacterBody2D

signal position_changed(y)

var speed = 900
var movement = Vector2(-speed, 0)
var can_move = false
var punkt = 0
var can_add_score = true

func _physics_process(delta):
	rotation += 0.99
	if can_move == true:
		var collision_info = move_and_collide(movement * delta)
		emit_signal("position_changed", position.y)
		
		if collision_info:
			if collision_info.get_collider().name == "Spieler" or collision_info.get_collider().name == "Spieler2" or collision_info.get_collider().name == "Gegner":
				speed = -speed
				$Treffer.play()
				
				
				
				var diff = collision_info.get_collider().position.y - position.y
				var new_movement = Vector2(speed, -diff * 12)
				movement = new_movement
				
				if can_add_score == true:
					punkt += 1
					$Label.text = str(punkt)
					can_add_score = false
					await get_tree().create_timer(0.2).timeout
					can_add_score = true
		
			elif collision_info.get_collider().name == "Wand" or collision_info.get_collider().name == "Wand2":
				movement = movement.bounce(collision_info.get_normal())
				$Treffer.play()
			
			

Oh @sven, it’s nice to see you again. The problem is the score increases even though the ball is slightly colliding making it go from 1 → 3 instead of 1 → 2 etc. I could take a look at your code and see what I could use to help me out. Thanks!

1 Like

So I added the if/else condition and followed some of the format of your code, AND IT WORKED. The score now increases properly and isn’t having that skip anymore, I should really start using timers more :laughing:

Any ways an off-topic question from me, How do I make it so that the ball actually changes directions when hitting the paddle instead of just going left.

I’ll make a separate topic for this if there aren’t any more replies. But either way, Thanks to everyone who helped me out in this topic!

Try this
var diff = … position.x - position.x
worked well for me in the test.
I know that your paddle is down.

I’ll try it and see if it works, Thanks

That works, but now the same bug I had earlier is back. The ball goes slow when hitting the middle, but fast when hitting the edges of the paddle, How do I fix this?

So I think I’ve found what you’re looking for!
Look into the Inspector of Ball
Screenshot 2024-05-28 112912

Edith:
Well I think it has gotten better but it is not completely gone.

I already tried doing it from changing the value in (-diff * 4, speed) but I could try and see if it works.

Where do I find motion mode?

In the inspector of Character2D.

I found it, but it’s not really working either.

But it’s okay, I’ll make a separate topic for this problem later so that this topic can be left as solved, so I won’t really be responding here anymore.

Thanks to everyone who helped me out in this topic, I highly appreciate it!