How to spawn particles where a ball collides?

Godot Version

Godot 4.2.2


So I’m working on a Pong game with LOTS of progress so far! (Thanks to help from people in the forums) and I’m implementing a particle system (Thanks to @gertkeno for introducing me to it) where dust particles come off from where the ball collides (Like a Sub-Emitter), But I can’t quite wrap my head around how this would work. Can anyone explain to me how this could be done/achieved?

Any help would be appreciated! :smiley:

For the exact contact point it depends on how your ball is setup.

For a CharacterBody use get_last_slide_collision() or move_and_collide() with .get_position()

A RigidBody will need to override _integrate_forces(state) and loop through reported contacts (make sure contact monitoring is on and reporting more than 1 contact)

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
    var collision_idx: int = state.get_contact_count()
    while collision_idx > 0:
        collisions -= 1
        var dust_position: Vector2 = state.get_contact_local_position(collision_idx)
        # spawn particles here
1 Like

I’m using a CharacterBody so I’ll probably use the move_and_collide().get_position

Also how would you also change the direction it’s facing (e.g when hitting the paddle particles face up, when hitting the right wall, particles face left e.t.c)?

When I add the Move_and_Collide, it’s asking for one more function in the brackets. What should I add to it?

move_and_collide needs velocity. the direction the contact is facing is get_normal()

How would I apply it in code?
Also, the particle now only appears on the second collision of the Ball instead of all the time.

I can send my script if you need it

Yeah post a script! If it’s a characterbody it’s important to know how you were moving it beforehand

1 Like
if collision.get_collider().name == "Paddle":
		if collision.get_normal() != Vector2.UP:
	 # side of paddle
	if collision.get_collider().name == "Paddle" and %Timer.is_stopped():
		score += 1
		label.text = str(score)
		%Dust.position = move_and_collide(velocity).get_position()
		%Dust.emitting = true
		speed += 300
		%Dust.emitting = false
	if collision.get_collider().name == "Borders":
		%Dust.position = move_and_collide(velocity).get_position()
		%Dust.emitting = true

How is collision defined? it seems like this is a result of move_and_collide itself, and instead you need only collision.get_position() or collision.get_normal()

You can even see similar functions used here:

Oh! I was wondering why I still needed a move and collide, I’ll change it

Also for some the reason, the particles only show up when hitting the top border. I could fix that with that with a timer but I was wondering if there was another solution to this?

Could be from setting the %Dust position to global coordinates, it would be better to use %Dust.global_position = collision.get_position()

It sort of worked, but the collisions sometimes don’t register and there’s still none on the paddle.
Will a timer node work in this case?

seems like the timer is stopping the paddle from making dust. I would try making dust after these if statements, rather than part of any of them.

I haven’t actually implemented the timer (yet). But the reason I want to use one is change the particles to false when they’re true, since the particles are oneshot in order for them to emit again

ah you can call %Dust.restart() to re-emit them immediately

Still best make dust all the time, ifs or buts

Oh! I’ll try that.

It Works! The Particles now properly spawn where the ball hits, even somehow faces the right direction, One last thing now would be for the particles to not be in front of the paddles during their lifetime, But I can fix that.

Thank you so much once again for helping me out!

1 Like

I also have one more question, how does the get_normal function work and where can I learn about normals in general?

Surface normals are a vector that points away from a surface’s face. In 3D they can be more complicated but for 2D (0, 1) points up, meaning the surface is a floor (1, 0) points right meaning the surface is a wall and we’ve touched the right side of it.