help for a PANG-like : collision detection and neverending bouncing

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By nonomiyo

Hi ! I’m making a 2D platformer in which there are some balls bouncing around, which you have to avoid touching.

here is a PANG gameplay video, for a better understanding

My character is a KinematicBody2D and the balls are RigidBody2D instances. I have 2 issues :

1/ The balls are boucing thx to the integrated gravity system. I’d like them to keep bouncing at the same height forever. But even with the “Friction” setting set to 0 and the “Bounce” set to 5000, they bounce lower and lower on each rebound. Is there a way to do this ? Does it make sense for the balls to be RigidBody2Ds ?

2/ the character is physically colliding with the balls properly but how should I detect collisions to trigger a code ?
I’m looking for a signal like the one for Area2Ds called “on_body_entered(PhysicsBody2D)” but “on_body_entered(Node body)” doesn’t seem to work this way…

-Any help is welcome, Thank you !
(godot 3.1.1)

:bust_in_silhouette: Reply From: ichster

KinematicBodies2D don’t have those helpful collision signals probably because they are meant to be user-controlled and not use the advanced physics that the physics engine provides. They can detect collisions, but only when asked to (using functions like move_and_collide() and move_and_slide()). If you want to emit_signals or do some other processing upon collision with another physics body it might look something like this:

signal hit_ball

func _test_if_bouncy_ball(object):
    # could also do something like: object.is_type("RigidBody2d")
    if object.get_meta() == "i set all bouncy balls to have this exact meta data string using set_meta()":
        return true
    else:
        return false

func _react_to_hit_bouncy_ball():
    emit_signal("hit_ball")

func _physics_process(delta):
    # test the collisions created after calling move_and_slide() or similiar
	var slide_count = get_slide_count()
	if slide_count > 0:
		for idx in get_slide_count():
			var collision = get_slide_collision(idx)
			if _test_if_bouncy_ball(collision.get_collider()):
				_react_to_hit_bouncy_ball()

If you want to make same-height-every-bounce bouncy balls I would suggest using a KinematicBody2D (since it sounds like you don’t want to use the physics engine features like “Bounce” at all), and then just move in the direction of the mirrored normal of the collisions. To get this normal you would do something like this:

func reflect():
    # THIS WON'T WORK I'M JUST SHOWING THE FUNCTIONS YOU MIGHT USE
    var collision = get_slide_collision(0)
    var normal = collision.get_normal()
    velocity = normal * SPEED

thanks ichster, I’ll look into it this weekend ! :slight_smile:

nonomiyo | 2019-08-28 20:16

With your help, I ended up solving it this way :
I made the balls kinematicbodies2D then put this code in them :

func _physics_process(delta):
	velocity.y += gravity * delta
	
	var collision = move_and_collide(velocity * delta)
	if collision : 
		if collision.collider.name == "walls":
			velocity = velocity.bounce(collision.normal)
		else : 
			$ball_anim.play("ballcrash")
			if collision.collider.has_method("hit"):
				collision.collider.hit()

It’s working now, thanks ! :wink:

nonomiyo | 2019-08-31 14:43

Glad to see it, good job!

ichster | 2019-08-31 14:47