0 votes

I have an ongoing Godot 3 project basically a breakout clone, where a RigidBody ball will often hit against a stationary block without triggering any event to remove the block from the scene. While I have been able to adjust the CollisionShape2D to account for some issues, there are recurring issues where the ball object will bounce off the CollisionShape2Ds (typically the top and left sides) before registering. I am not sure what the cause could be. While resizing the collision shapes helps, its not perfect.

I'm using code from an old breakout demo linked here, and my source is located here. Any help would be appreciated.

asked Apr 22, 2018 in Engine by Cameron Kilgore (62 points)

1 Answer

+1 vote

Yay, another godot ludum dare project!

I had a look through your code, and there's a lot of things that aren't ideal. I recommend you spend some time with the physics introduction documentation.

Stick Collision

You have a KinematicBody, but instead of giving it a collision shape, you added a child StaticBody that gets a collisionshape, and then the area 2d is a child of the static body?

This basically comes down to this question: for collisions between the ball and the paddle, do you want to handle it, or do you want the physics engine to handle it? The physics engine won't calculate fancy angles if you want the bounces to be unpredictable (like breakout) but if you don't care about that then it doesn't matter.

If you want the physics engine to handle collisions:

Stick (KinematicBody2D)
-- CollisionShape2D
-- Sprite

And that's it. You don't need an area2d or a staticbody. When the ball hits the paddle, it'll bounce off.

If you want to handle the collisions / bounce logic for paddle/ball collisions, here's how I would do it:

Stick (Node2D)
-- Area2D
-- -- CollisionShape2D

You don't need a static body (or a kinematic body!). You'd have to change the moveandslide logic in the stick to just setting a position, but that's fine. You would use bodyentered on the area2D to find out when a "collision" happened, and you could affect the ball in that way. You would probably also need the bodyexited signal from the Area2D so you don't affect the ball multiple times per collision, if that makes sense.

puck velocity shenanigans

This one's pretty quick, and basically boils down to this: As a general rule, you should never ever use set_linear_velocity (no linear_velocity = blah either) on a rigid body. From the physics intro:

You do not control a RigidBody2D directly, but instead you apply forces to it (gravity, impulses, etc.) and the physics engine calculates the resulting movement.

I can't tell if you're actually calling adjust_angle function on the puck anywhere, so maybe it's not actually causing issues, but for future reference, you should be using apply_impulse instead. Something like this:

if linear_velocity.length() < min_speed:
  # puck is moving too slowly, speed it up

   # impulse will make up the difference between speed we're going and speed we want to be going:
  var impulse_size = min_speed - linear_velocity.length()

  # set the impulse in the same direction of travel as the puck
  var impulse = linear_velocity.normalized() * impulse_size

  # actually apply the impulse
  apply_impulse(Vector2(), impulse)

Brick Collision

Okay, so here's the answer you were actually looking for.

boring explanation

Your bricks are static bodies with area2Ds. The static bodies have collision shapes (that you're not listening to) while the area2Ds also have collision shapes (that you are listening to). The two collision shapes overlap, but not exactly (the area2D is a little bit smaller than the static body!). When the puck hits a brick, it bounces off the static body's collision shape, which means if the physics engine was perfect, the area2D would never report any collision (since its shape is completely inside the staticbody's shape). However, shapes have to overlap just a tiny amount for collisions to happen. Thus, sometimes when the puck hits a brick it overlaps the static body's shape far enough to also hit the area2D's shape. This happens more often on the bottom and right sides since there's less gap between the static body shape and area2D shape there.

Solution

If you want collision reporting on a physics body that's not supposed to move, you should be using a RigidBody2D in Static mode with Contact Monitor set to true and Contacts Reported set to something greater than 0. Then you can listen to the rigid body's body_entered signal and put all the collision logic there.

Brick layout:

Brick (RigidBody2D)
-- Sprite
-- CollisionShape2D
-- Timer

Bonus points if you make brick into it's own scene (right click -> save branch as scene) that you instance into the game scene, since that means way less work in changing all these bricks into rigid bodies.

Wow, this answer got away from me a bit

What a wall of text! Let me know if you need more info, I'm happy to try to explain things further.

answered May 11, 2018 by markopolo (618 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.