Breakout Clone 2: Colliders!

2023-02-06

Getting the ball to bounce correctly off blocks requires a bit more thinking than how we have it bouncing off of the walls or the top of the paddle. I also want to prevent the paddle from moving through walls so that it remains inside the play area.

The problem with the paddle is a tricky one. Both the paddle and the walls have colliders on them with the isTrigger flag set to true. This means that normal physics-based collisions, like one object being prevented from moving through another, will be ignored, and instead the OnTriggerEnter2D function will be called on the two objects. Since the ball in this game is the thing moving about the play area, interacting with other things, I attached this method to the ball object itself. See my previous post where I used this method.

If I stick with my current approach, then I would need to add an OnTriggerEnter2D method to my paddle object, detect when the paddle is about to collide with the wall, and reset the paddle's position to just before that collision would occur. Since the position of the paddle object is at the center of the paddle itself, I would need to adjust the paddle position to be offset based on 50% of the width of the paddle, plus a little more space to ensure the colliders are out of the way. If I don't add a little extra space, then the objects will always be "colliding" and the paddle will essentially become frozen.

But wait! Isn't this what game engines are supposed to do for us?

In Unity, two game objects with the Rigidbody and Collider components will react in a relatively realistic manner. They'll even be affected by gravity. We don't need gravity in this game, but to get the collisions we want, I won't be able to use the isTrigger method anymore, which means I'll need to use a different method when detecting that ball is colliding with different surfaces. Thankfully Unity supports this, and instead of registering the OnTriggerEnter2D method on my ball object, I'll need to instead use OnCollisionEnter2D:

  void OnCollisionEnter2D(Collision2D collision) {
    string tag = collision.gameObject.tag;

    if (tag == "Block" || tag == "Wall" || tag == "Paddle") {
      Vector2 currentVelocity = rigidBody2D.velocity;

      // A vector perpendicular to the surface we're colliding with
      Vector2 normal = collision.GetContact(0).normal;

      // calculate the new, reflected velocity
      Vector2 newVelocity = Vector2.Reflect(currentVelocity, normal);

      rigidBody2D.velocity = newVelocity;
    }

    if (tag == "Bottom Wall") {
      BottomHit(); // Ends the game
    }
  }

We'll also add in some reflection math so that the ball bounces off of surfaces appropriately depending on which side of that surface it collides with.

I can now set the walls to static:

The ball to kinematic:

And the paddle to dynamic:

And everything collides as expected!

Next I added in a Block object with some colliders and made sure everything works:

Next up: making our blocks destructible.