Recreating Pong in Godot

Or, as my three year old calls it, "Poooiiiiinnggg"

I love games—board games, video games, made-up games. I remember as a kid, I once made an entire board game (though I wish I remembered what it was) and crafted all the little cards and pieces. I have fond memories of my brother and me playing video games together as kids (and even now as adults). My dream has always been to be a part of the games industry in some way, whether as a journalist, a streamer, or a developer. It wasn’t until I started a coding bootcamp that I thought, “Maybe I could learn to develop games.” And so, here I am, teaching myself how to use Godot. Maybe one day, I’ll develop that dream game. Who knows!

One of the first roadblocks I hit when learning Godot was deciding where to start. With so many tutorials out there, I often found myself paralyzed by choice, trying to pick the “perfect” one instead of just diving in. Eventually, I discovered a tutorial by GDQuest, which was great for introducing me to the Godot Engine. But after completing it, I didn’t feel like I had truly grasped the concepts beyond copying and pasting code. So, I did what many of us do—I went on Reddit. There, I stumbled upon the 20 Games Challenge. This challenge was exactly what I needed: some structure to keep me on track without being a step-by-step walkthrough. The challenge provided definitions of done for each game, leaving me to figure out how to achieve those goals. The first game on the list: Pong.

pong sketch

Day 1: Building the Basics

I got further than expected on Day 1. I broke the game down into smaller parts and started with creating the game area, including walls and a net. I used StaticBody2D nodes for the walls and added collision shapes so the ball could bounce off them. Next, I created the player paddle using a CharacterBody2D with its own collision shape, since it needed to move with user input. To make the paddle move, I figured out how to constrain its movement to the y-axis within the game window, ensuring it wouldn’t move out of bounds. Setting up user input was straightforward, involving just a couple of if statements to control movement with the W and S keys. Success!

Then, I moved on to creating the ball using a RigidBody2D. I wrote a simple script to make the ball move and bounce off the paddles and walls. The ball physics worked well at first, but I encountered issues later. I also added a second paddle, but it didn’t behave as expected. Despite my efforts, the paddle could move out of bounds at the bottom and didn’t reach the top of the game area. I decided to tackle this issue the next day as it was time to pick up my son from daycare.

Day 2: Adding Features

I was excited to get back to it. I really noticed I was getting into that flow state, and it was something I had been missing the past few months. I love learning, and I love how direct the feedback is when you’re coding. You can immediately see whether or not something is working as expected. I was really enjoying this.

With a fresh mind, I quickly identified and fixed the issue with the second paddle. Now, both paddles were working, and the ball was bouncing correctly. I then created a restart scene, as my partner suggested, since the ball wasn’t resetting yet. Implementing the restart menu was straightforward: the game checks if the ball goes out of bounds and triggers the UI menu with a restart button.

Next, I tackled scoring. While the score tracker worked, it was pointless without a proper ball reset mechanism. I spent most of Day 2 and Day 3 trying to fix this. Despite numerous attempts and debugging, I couldn’t resolve why the ball would reset out of bounds after a few successful resets. Even ChatGPT’s suggestions didn’t work. Fortunately, the 20 Games Challenge Discord came to the rescue. A fellow participant not only provided revised code but also explained why my approach wasn’t working. Understanding that RigidBody2D can exhibit unusual behavior when modifying position and velocity directly helped me resolve the issue. The ball reset beautifully after updating the code.

ball logic

This was causing issues with ball reset logic.

Day 3: Refining the Game

On Day 3, I updated the score tracker and implemented a game over screen that triggers when a player reaches 10 points. This was simpler than I expected, accomplished with a simple if/else statement.

Goals for Pong:

With these goals met, the game was technically complete. I still had some stretch goals like adding sound and an AI paddle. I attempted to add sound effects for when the ball hits the paddle, but I encountered an issue. Currently, the game plays a “poing” sound when the game over screen appears, a sound lovingly provided by my son. For now, I’m calling it DONE.

Result:

You can checkout the source code on my Github or play the game directly.

Final Thoughts:

This project was incredibly rewarding. I was thrilled to see a semi-working version of Pong and couldn’t wait to share it with my family. Watching my partner and my three-year-old son play the game, even in its rough state, and hearing them laugh was the best feeling. My son’s enthusiastic “Wow, this is cool!” was priceless and made all the effort worthwhile. I look forward to the day when I can create a fully original game for him to enjoy. This experience has reinforced the joy of problem-solving, the value of community support, and the importance of taking breaks. I’m excited to continue learning and developing new games.