Coding Challenge: Air Hockey Game

Coding Challenge: Air Hockey Game

Published: Sep 8, 2025

In this coding challenge I made an air hockey game with Javascript. I set out to make a game that simulated the real physics of air hockey with paddle-puck collision with force-based momentum transfer.

My goal was for the game to approximate the feeling of playing real air hockey. I wanted the game to have physics and feedback that felt satisfying. I also wanted to explore making a computer player that was fun to play against.

You can interact with the project full screen on Codepen: https://codepen.io/fleemaja/full/OPyqWBL. Use your cursor's position to control the blue paddle. You can also see the project within this blog post here:

I made my version of the game with the help of a JavaScript library called p5.js. This library provides tools to create interactive graphical programs for the web. It simplifies the interface of programming with Canvas, an HTML element used to draw graphics via JavaScript.

I have quite a bit of experience messing around with p5.js thanks to years of following a great Youtube channel called The Coding Train. This channel features hundreds of videos exploring creative coding, the intersection between coding, math, algorithms, art and design. This channel has dozens of videos exploring how to simulate physics and on how to make 2D games, so it has provided me with a good background to take on this air hockey challenge.

Before starting my game, I was curious how the AI LLMs like ChatGPT would do if I prompted them to make me an air hockey game with Javascript. They ended up giving me extremely simple and wonky games with physics that were bizarre and computer players that behaved oddly. The games were totally unplayable.

Not being able to make a relatively simple 2D game with clearly defined elements and rules, I don’t feel like AI will be taking all of our jobs anytime soon. It is incredible that they can spit out something even resembling whatever you prompt and giving you an organized guide to what they’ve made though. And they can be a great help as an assistant when you need a specific problem solved or some boilerplate code.

To begin building my game I decided I would focus on starting simple: with drawing a rectangular play area, a paddle that the user would control with their mouse position, and a puck that the user could knock around the arena. This was the most essential part of the game for me, getting the physics of the puck to feel right. So, I spent a long time just honing how the puck and paddle collided and moved in a little sandbox arena.

Once I got the puck moving around the arena in a way that felt satisfying, I added goals and a scoreboard. This was another challenge. I had some weird behavior near the edges of the goals. Shots coming in at wide angles would suddenly reset back in the arena, looking bizarre. I had to think about at what point the puck had passed the threshold of the goal and could be counted as a score. I had to implement a system where it passed a threshold and then got sucked into the goal like it was falling in a real physical air hockey game to help avoid bugs. I also made sure to reset the puck when goals were scored to the player who just got scored on whose turn it was to serve.

Then I added a computer player, giving it a red color and the player a blue color. I color coded the scoreboard and added a color coded “GOAL!” message when a score was made.

I don’t have much experience making computer players in games, so I looked up how to do it. The internet told me to use a “state machine”, setting the computer player's behavioral algorithm based upon current conditions in the game. I gave the player three states: defend, attack, and possession. The player would run a certain algorithm conditional to the game’s current conditions like which half of the arena the puck was on and how fast the puck was going.

The computer would run an algorithm for defending when the puck was on the other side of the arena. It would follow the x position of the puck with a bit of “smooth randomness” from a Perlin noise generated offset value. Its position would be clamped to near the goal to put itself in a good defensive position. The computer ran an attack algorithm when it saw a good opportunity to shoot once the puck was on its side of the arena. The computer would have to calculate how to approach the puck to strike it near the player’s goal. The possession state depended on the puck going below a certain speed threshold on the computer’s side of the arena for a certain amount of time. The computer would wait for the puck to slow down and then switch to attack mode and strike the puck at the player’s goal.

These algorithms are currently not perfect at all. The computer has trouble putting itself in position to shoot a straight shot at the player’s goal when the puck is going side-to-side or near the walls. But I was satisfied with the imperfection of the computer’s aim, because if you were not paying attention it would seem human-like in its imperfections. The computer would sometimes hit shots off the wall at the player’s goal due to the imperfection in the algorithm too, which was a nice unintended side effect.

Finally, I added adaptive difficulty to the game where certain variables in the computer’s algorithm would be dependent on the current score. The computer would get faster, shoot faster, and defend tighter to the goal when it was losing. It would loosen up and go slower when it was winning. This made the game much more fun and interesting to play. Pretty much every time I play the game, the game ends up being pretty close. The AI algorithm doesn’t seem perfect at all, but I think it ended up being fun to play against.

I wanted to make the game feel good, with feedback that felt satisfying. So I added a screen shake effect on collisions and when goals were scored to emphasize the physicality of the game. I added a sparks effect to provide more feedback for collisions as well. The sparks are procedural generated little particles that shoot out and fade away when collisions happen.

I then added a game over screen with a rematch button after 7 goals (which is apparently the standard “winning score” for air hockey). The screen overlays the canvas when the game over condition is true and displays who won the game, the final score, and a rematch button. The rematch button isn’t actually an HTML button, but a rectangle that the code detects the user’s mouse position within and then changes the cursor or detects click events.

At first when I made this overlay, the rematch button was hovering near where the puck would be reset, and the user’s mouse position was causing unintentional hits of the puck to kick off the game. So, I moved the rematch button to the bottom of the screen away from the puck and near the player’s goal.

Next, I added sound effects. This is something that the help of an LLM really impressed me with. I asked the LLM to create the sound effects using a procedural generated synth. It suggested using the p5 sound library and came up with some code for interesting synth sound effects with several cryptic settings. The sounds it came up with at first were very cartoonish, so I asked for more realistic clacking sounds of the puck, and it came with some subtle sounds that I think are pretty good. I’m not that familiar with sound design or engineering so this was very helpful for me. It would have taken a lot of googling and reading through documentation for me to put together code for these synth sound effects that are more nuanced than simple notes with a sine or sawtooth synth.

I then added a mute button in the top right corner to give the user the option to turn off the sounds if they found them annoying. This works like the rematch button.

The most frustrating part of web development to me is having to design for such a wide variety of window sizes, browsers, operating systems, etc. I had to ensure that the canvas was drawn at a certain aspect ratio for every possible screen size. I had to make sure that everything in the code was set to a size related to the canvas’s width or height to ensure that the game was the same no matter what size screen you play it on. I also had to add touch screen controls to let users on touch devices play it. I had to add a function that resized every component of the game when the window was resized also. There are also challenges with uploading to Codepen, which embeds your sketch within its interface, adding things like a toolbar that complicates window size calculations.

This air hockey challenge was a project that taught me several things. It was challenging trying to implement physics that felt life-like. It was fascinating to try to code the behavior of an AI player. I am eager to learn more about game AI in future projects. While this game is certainly far from perfect, I think it is pretty fun to play and does meet my goal of feeling satisfying.