Purpose and Goal

Asteroids was one of my favorite arcade games growing up. I wanted to recreate that nostalgic experience while leveling up my web development skills. I was excited to build a game because I knew it would be a great way to learn many aspects of programming - state management, collision detection, animations, etc.


I started by following a YouTube Tutorial to get the basic gameplay working. This initial version was not very maintainable, with all 700 lines of code crammed into a single <script> tag within an HTML page. I embarked on a major refactor from that tutorial, splitting the code into modules and converting the vanilla JS to TypeScript. This significantly improved the structure and maintainability of the code base. From there, I just started adding features like procedurally generated asteroids, a global scoreboard, and more!

Tech Stack Explanation

I avoided frameworks to keep things simple since most of the logic lies in the HTML5 canvas. I firmly believe that complexity should only be introduced when absolutely necessary.

For example, when I started GeoAsteroids, the scoring was done client-side in the browser. It was only when I wanted to implement a global high scoreboard that I started using a database. I chose MongoDB because high scores are essentially a flat JSON file, and a NoSQL database is a perfect fit. If my application had needed to perform a lot of joins, I might have opted for something like Postgres.

To communicate with MongoDB, I chose to use Vercel serverless functions. I think this is a good choice because the only time I am querying the database is when users visit the high score board or submit a new high score. Both of these actions happen infrequently, so they are a perfect fit for a serverless function.

Lessons Learned

Working on this project taught me a lot about managing states across frames and preventing unintended side effects. In a videogame, you must keep track of what is animating in each frame and which pieces of code are mutating game objects. Initially, I ran into countless issues where objects were being changed unexpectedly. One of the ways I mitigated that issue was by using getters and setters on each object. This way, there was only 'one way' to modify the objects.

Another thing that is now ingrained in me is the importance of testing and typing. Now that my application has over 80% code coverage, I can perform refactorings efficiently, knowing which functions are being broken without ever having to run the server to iterate for bugs. It also has helped lessen the cognitive load when developing new features because the types guide me as I write new code.


Back to Home
John Solly Profile Picture
John Solly Profile Picture

John Solly

Hi, I'm John, a Software Engineer with a decade of experience building, deploying, and maintaining cloud-native geospatial solutions. I currently serve as a senior software engineer at New Light Technologies (NLT), where I work on a variety of infrastructure and application development projects.

Throughout my career, I've built applications on platforms like Esri and Mapbox while also leveraging open-source GIS technologies such as OpenLayers, GeoServer, and GDAL. This blog is where I share useful articles with the GeoDev community. Check out my portfolio to see my latest work!