I was on my last internship, and for the first time in the entire four months I had nothing to do. So I started writing this game in pure javascript. I got pretty far but started to run into some very tricky bugs. I thought that I was nearly there, just needed to make some tweaks but that was not the case. It took many more hours to finally figure out error handling and I had to refactor the app a couple times. First to object oriented javascript, then to typescript.
I spent a little too much time hanging out with comp sci nerds and found myself writing a lot of functional code. I like pure functions, I use map and reduce a ton in javascript, but games are not the best use case for functional programming. They have a lot of state, and having all that state in 1 place is very confusing. The game was setup so there was a large object that contained all the state, and the last call in the pipeline would be to get the next frame by rerunning itself.
The first version would then call a bunch of functions on different parts of the code to update the different components. It was hard to think about a game functionally because the data is mostly sitting still and changing. So I refactored the codebase to OOP javascript
After refactoring the game to OOP javascript, I ran into many new problems. The game was much easier to think about, but I ran into null errors everywhere!
I also seperated the game logic into a Stage
object because I wanted to have a menu stage, but never really got aroundto it.
The game would run fine, until a collision or something and then I’d get a null error because I forgot to pass a variable into X.
After refactoring to Typescript, and fixing all the null errors the project got a lot more interesting. I setup all the types, and added a vector class for the ball velocity.
Now I could finally fix the collision handling bugs. I got horizontal collisions working pretty quickly, but the ball would glitch through the paddle if there was a horizontal element to the collision. I thought, that I could just reset the position of the ball on collision detection and reverse the velocity. But then the paddle would still get into the ball and the behavior after that was unpredictable.
I learned quickly that I needed to reset the position of the paddle as well! I thought this would be annoying for the user, having their paddle stopped by the ball, but it’s so fast that the slight lack of position update is unnoticeable.
Ok, now collisions were working. But I was inverting the horizontal velocity of the ball on every collision.
I needed a way to detect if there was a horizontal or vertical condition or horizontal! I tried comparing the center of the paddle and the ball, but it wasn’t 100% accurate. There were still a lot of weird bugs, like horizontal collisions being treated as diagonal.
I did some research and learned that game engines apply physics in 1 dimesion at a time, then they can detect collisions by simulating the next frame.
Implementing this was a headache because I had to decouple the X and Y dimension update and couple the velocity change and collision detection.
When that was done for the ball and paddle, I made a BallPaddleCollisionDetector
so the 2 paddles and ball wouldn’t need to all know about each other,
they communicated through the collision detector for their only interaction (Collisions).
The end result looked like this:
The document is called to find the canvas element with the correct id, and to add event listeners for keyboard input. The HTMLCanvasRenderer is used by the renderer and technically fetched by the Game object, but the Game object doesn’t use the HTMLCanvasRenderer at all.
The code can be found here: Repo
If you’re on desktop, you can play the game below. I’m happy with how it turned out, maybe sometime I’ll get around to writing a menu stage for it.
W and S for the left paddle
Up and Down for the right paddle
Please use a larger screen to play