Porting Games to the Web with WebAssembly

How to port an Asteroids game from C to WebAssembly 🎮

WebAssembly is a new language for the web. Much like low-level assembly languages, however, very few people write WebAssembly by hand; instead, you can compile code written in other languages (e.g. C, C++ and Rust) to WebAssembly and run that code in the browser.

Why would you ever want to do that, you ask? One reason is portability: WebAssembly makes it easier to port existing games, desktop applications, and command-line tools to the web. Another reason is the potential for speeding up web apps by replacing slow JavaScript calculations with compiled WebAssembly.

In this article, we’ll focus on how to port an open-source clone of the classic Asteroids game from C to WebAssembly.

For a preview of the final result, check out this live demo.

Let’s get started!

To compile this game, we’ll use Emscripten, a tool that helps you compile C and C++ programs to WebAssembly. As we’ll see, developing in WebAssembly is not easy, but Emscripten provides many tools and features that make it much easier.

To install Emscripten, you can pull this Docker image I put together that contains all the tools you’ll need for this article (you can also install Emscripten from scratch, but that may take a while):

Inside the container, let’s clone the repo. We’ll check out a specific commit ID, in case the code changes after this article is published:

Interestingly, if you try to compile this code as is to WebAssembly, your browser tab will crash because of the infinite loops in the code!

A series of unfortunate loops

Games often contain infinite loops that wait around for user input, mouse movement or an animation to finish. For example, you’ll see the following infinite loop if you dive into the Asteroids code (asteroids/main.c) — here’s the equivalent pseudocode:

While using infinite loops works in a desktop game, this won’t fly in the browser, where infinite loops will crash your tab (details here).

What this means is that we’ll have to restructure the while() loop above into something the browser can handle, i.e. running the contents of that loop periodically instead of continuously. In general, we can use Emscripten’s emscripten_set_main_loop() function in our C++ code to define a function to call periodically:

So let’s replace this infinite loop; here’s pseudocode to illustrate what we need to change in the code:

As you can see, there’s a fair bit of moving code around to adapt it to the browser. The final main.c is available here (see diff here).

Now that our game has been un-infinite-loop-ified — a valid scrabble word, I’m sure — we’re ready to compile our game!

Compiling the game

Let’s see how we would usually compile this game to binary, and then which modifications we need to compile it to WebAssembly. According to the README file, we can compile the Asteroids game as follows:

Instead, to compile it to WebAssembly, we’ll use Emscripten’s gcc wrapper: emcc.

Like many games written in C/C++, Asteroids uses the SDL library, which is short for Simple DirectMedia Layer. In a nutshell, it’s a library with useful utility functions to handle user input via mouse/keyboard/joystick, play audio files, and more. Because SDL is so popular, it has already been ported to WebAssembly, and Emscripten provides special flags to support it out of the box; here’s what the emcc invocation looks like (differences in bold):

Let’s unwrap this:

  1. We modified the output to be app.html so that Emscripten generates HTML and JavaScript files that will conveniently initialize our WebAssembly module (app.wasm) and load the game in an HTML canvas.
  2. Instead of calling sdl2-config, we use the Emscripten flag USE_SDL to use the SDL2 library.

If you launch app.html, you should now be able to play Asteroids in your browser:

Congratulations, you just ported a game to WebAssembly!

Fun exercise: to make this game more interesting, set BULLETS=100 in the file asteroids/player.h 😄

The full code is available on GitHub.

A live demo is available here.

Ready for more?

If you’d like to dig deeper into how to port more interesting/complex games to the web such as Pacman (screenshot below), or if you want to learn how to get started using WebAssembly in your own web applications, check out my book Level up with WebAssembly.

Bioinformatics Software Engineer at Invitae, Author of “Level up with WebAssembly”.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store