Inspiration

The Fairchild Channel F was the first ever video game console to use physical cartridges. Releasing in 1976, there were a multitude of classic games that were released for the system. One of which was Tennis, being a slightly more advanced version of Pong. My goal was to capture that retro feel while also upgrading that version of Pong to make a simple concept into a fun and enjoyable experience.

What it does

Battle Pong is a two-player arcade game inspired by the Tennis game on the Fairchild Channel F. Players control paddles that can move freely in 2D, rotate continuously, and use two special abilities - a Dash that bursts the paddle forward and sends the ball flying faster on impact, and a Quake that detonates a shockwave pushing the opponent away. Goals are scored by getting the ball through a small opening in the center of each wall rather than the full side, making positioning and angles much more deliberate than classic Pong. Each player also controls a Goalie, which is a smaller blocker that defends the goal zone. The first to 3 points wins. The title screen features a full rhythm game-style visualizer with 24 frequency bars synced to the music, a bouncing title card, and a scrolling retrowave perspective grid.

How I built it

I built entirely in JavaScript using Phaser 3 as the game engine, bundled with Vite. The game is structured around Phaser's scene system - a title screen, mode select, settings, and the game arena are each their own scene class. Gameplay objects (Paddle, Ball, Goalie, PowerUp) are standalone classes that the Game scene orchestrates. Paddle collision uses a custom rotated rectangle solver rather than Phaser's built-in arcade physics, so the ball reflects correctly off angled paddles. The beat-synced visualizer on the title screen was built by running the soundtrack through a Python/librosa STFT analysis pipeline offline, exporting 24 frequency bands across the full track into a JSON file that Phaser reads at runtime, where no real-time audio analysis needed in the browser.

Challenges I ran into

The biggest challenge was the pause system, which still has a minor issue. Phaser's internal timer, used for the ball launch countdown after each goal, keeps running even when gameplay is gated behind a pause, so pausing at exactly the wrong moment would let the ball launch into a frozen game, creating an unrecoverable deadlock. A related issue was that the ball's trail spawned using a fixed += 16ms accumulator rather than real delta time, causing a burst of ghost images after unpausing. Rotated paddle collision was also a big challenge, as getting the ball to reflect properly off a paddle at arbitrary angles required projecting into the paddle's local coordinate space and solving overlap there before reflecting the velocity vector. Finally, the main issue involved the sprint spawning of the Quake power up, which would freeze the game if at an unlucky time. This required going into the console to verify the issue to address the spawning system so that way the game wouldn't crash.

Accomplishments that I'm proud of

The beat-synced title screen turned out well, where rather than approximating it with a simple timer, the track was actually analyzed with a full short-time Fourier transform, and the resulting per-frame frequency data drives 24 individual bars in real time, with peak-hold dots and mirrored top bars, all color-graded bass-to-treble. The rotated paddle physics also feel noticeably better than standard axis-aligned Pong, where hitting the ball at an angle with a rotated paddle and watching it redirect in a way that feels physically correct was a satisfying result. The Dash and Quake abilities add a meaningful layer of decision-making without complicating the core concept. Finally, the overall aesthetic and controls took a long time to refine, which I believe is essentially in order to make a fun experience.

What I learned

Phaser's arcade physics system is fast and convenient for simple cases but breaks down quickly with rotated colliders, where sometimes it is faster to write a custom narrow-phase solver than to fight the engine. I also learned that pause systems in games with timers are deceptively complex; any delayed action needs to be aware of game state at the time it fires, not just at the time it was scheduled. On the audio side, pre-baking frequency data offline and shipping it as JSON is a practical way to get music-reactive visuals in a browser without the complexity or latency of the Web Audio API's AnalyserNode. Overall, it was a good way to learn more about a web-development games and the process of making a game from scratch, such as with gameplay, audio, and animation.

What's next for Battle Pong

Online multiplayer is the most obvious next step, as the mode select screen already has a placeholder for it. Beyond that, a proper 1-player CPU opponent using some AI for the paddle, more powerup types, additional arena layouts with different barrier configurations, and a proper soundtrack selection screen could all extend the game meaningfully. On the visual side, adding more to the procedurally generated paddle and ball textures with hand-crafted assets in the retrowave style would bring the aesthetic closer to something to like Osu! or Muse Dash. Finally, I would also go look into upgrading the sound effects, animation, and gameplay experience to make it as appealing and smooth as possible.

Built With

Share this project:

Updates