Building Pong with Zig and Raylib #6: Font Size, Collision Bugs, and Refactors
In this one, we’ll tidy up our Pong implementation by addressing three key issues:
- The score font is too small
- The ball can get stuck inside a paddle
- Trigger score on edge (not the middle) of the ball going past.
We’ll also refactor score tracking to better match game logic structure.
🖋️ Make the Score Font More Readable
The score text was a little too small. If you’re using dvui, here’s how to
adjust it:
| |
Thanks to code sample from milogreg
You may also need to adjust the width and height of the container if the larger font gets clipped. In our case, font size of 64 felt about right.
🧱 Fix the Ball Getting Stuck in the Paddle
When the ball moves too far in one frame, it can land inside the paddle and bounce back and forth infinitely.
This trap happens because we just multiply the x-velocity with -1 to reverse
direction.
One way to fix this is to only trigger the bounce if the ball is moving toward the paddle. For example:
| |
Thanks again to code sample from milogreg
This ensures we don’t apply the bounce logic when the ball is already inside the paddle.
Another (potential) way to fix this would be to change the collision logic to fix the x direction based on whether it’s the left or right paddle.
🧮 Trigger a Score When the Ball’s Edge Crosses the Screen
Previously, we checked whether the ball’s center (ball.x) crossed the
screen edge. Particularly with the ball being bigger than the paddle, this
caused issues when the top/bottom of the paddle hit the ball.
| |
This triggers the score as soon as the edge of the ball crosses the screen bounds.
🔄 Refactor: Move Scores Out of the Paddle Struct
Storing the score inside the Paddle struct is convenient but semantically odd
- paddles shouldn’t own scores. Instead, let’s move them into your
Gamestruct:
Then, pass the score explicitly to the rendering function.
You can find the updated code in Game.zig .
✅ Bonus Fix: Make Score Display Use Paddle Play Area
We now compute each paddle’s play area (a dvui.Rect) and use it to position
the score label, keeping layout logic more re-usable.
We add a play_area field or method to our Paddle struct that returns its
side of the screen. This makes the rendering logic clearer and more flexible.
⏭️ What’s Next?
Next episode: adding a pause menu to Pong, based on what I just built for my other game, triangle. We’ll add basic Resume/Quit options and freeze game state mid-play.
Links
- Watch Video
- Source Code (at this point)
- Prev: Smarter Collisions & Cleaner Code
- Next: Pause Menu