Asteroid WASM - Click here to play
So as you can I have created a game - Atari Asteroids clone. Well, it’s not exactly that I created it now, this is actually a project of mine that I had created almost a year back (autumn of 2020). This project is quite special to me because a lot of things had lead up the creation of it and I want to keep these memories if nto for others then at least for myself in a preserved medium — this blogpost.
The journey
So how did I come to the conclusion that I need to create something like this? I didn’t. Life put this project in my lap. This project is a direct successor to the fact I only wanted to try out WebAssembly. I’ll put this shortly:
- I was a web dev at my first workplace, where I had been working for about a year (working part time while studying) and emerging web technologies like WebAssembly seemed quite interesting to me. So after googling a bit, it turns out that Rust has amazing WebAssembly support. Might as well learn it, what could be so hard about it …? Let’s just say that I went into a rabbit hole that I still haven’t crawled out of — nearly 2 years later (as of writing this).
- While learning Rust I had gotten to a point where I felt that I was productive enough for some small projects, CLI tools, data scrapers and parsers — TIME TO COMPILE TO WEBASSEMBLY! But I didn’t really have anything to compile to WASM. So I tried creating some simple things like counters and calculators, but none of that really seemed to be stimulating enough. So I decided that this is the perfect time to learn WebGL… but there were no examples of Rust + WebGL integration on the internet. So I attempted to follow javascript tutorials for WebGL, writing the code in Rust. This approach seemed to work well enough, I managed to render some shapes and apply transformations to them via JS-WASM integration.
- Alright, the next chapter was when I joined the local Machine Learning course (it happened in the middle of the COVID waves, when the disease wasn’t very widespread). So one of the tasks was to get a hang of linear algebra that’s necessary for manipulating data and work with matrices — create a simple Asteroids game using matplotlib in Python. While creating it, I came to the conclusion that I enjoy the game programming way more than the actual ML stuff. So initially I tried recreating the game in bevy using Rust but that turned out quite bad…
- Although soon after that (I was still an undergrad student at that time) we got a new final project to do for our schools web technology course. The requirements for it were quite simple — create a simple React app, integrate a non-SQL database and use Express.js for the backend. Because I had been a full stack web developer for 2 years at that point, the base requirements seemed simple enough for me to do in 2 evenings. But there was this itch at the back of my mind. Asteroids. WebGL. Rust. And that’s how the idea was born to combine everything I had learned into a single project that you can experience yourself (although a stripped down version, I have removed all of the bloat - the backend and the database).
Technicalities
Let’s start off with the technical details of the project. The frontend is written in React/Typescript, but the actual game is completely written in Rust (god I love this language). The Rust code gets compiled to WebAssembly using wasm-bindgen, which also allows me to easily inject Javascript APIs and callbacks that are necessary for proper state management in my React app. All of the UI like the buttons to start a game, etc. are rendered in React, positioned above the WebGL canvas. The WebGL canvas gets passed to the WASM (Asteroids game) instance and the buttons interact with the said instances public API (for example to start the game or display the hearts or the score). The code sample below shows how callbacks and game initialisation is being done:
/* Set the factual renderable object */
useEffect(() => {
if (gameState === GameState.RUNNING) {
client?.set_renderable(
wasm.RenderableOption.Asteroid,
new wasm.Transform(0, 0, 0)
);
client?.set_score_function((scoreNew: number, livesNew: number) => {
setScore(scoreNew);
setLives(livesNew);
});
}
}, [client, gameState, wasm.RenderableOption.Asteroid, wasm.Transform]);
I wrote a custom “game engine” for this game as well — the spaceship, asteroids, the movement was hand-coded from scratch by me, as well as the whole rendering process and WebGL calls and shaders (I doubt that the white line “shader” can be called a shader). The only libraries I used well, for WASM compilation and some matrix mathematics libraries. This accomplishment makes me quite proud. I’ve added some sample code below so you can get a feeling of how most of the code base looked like:
fn init_buffers(gl: &GL) -> (i32, i32, WebGlBuffer) {
let position_buffer = gl.create_buffer().unwrap();
gl.bind_buffer(GL::ARRAY_BUFFER, Some(&position_buffer));
// Construct bullets
let vertices: Vec<(f32, f32, f32)> = vec![(0., 0.5, 0.), (0., 0., 0.)];
let mut result_array: Vec<f32> = Vec::new();
for elem in vertices.iter() {
result_array.push(elem.0);
result_array.push(elem.1);
result_array.push(elem.2);
}
unsafe { // Yes I had to `unsafe` :)
let vert_array = js_sys::Float32Array::view(&result_array);
gl.buffer_data_with_array_buffer_view(GL::ARRAY_BUFFER, &vert_array, GL::STATIC_DRAW);
}
(3, 2, position_buffer)
}
To do a little bit of humble bragging - when writing piece of code, I was only a third year bachelors Computer Science student, all of this was self-taught (but I’d wish to have received some education in computer graphics programming).
Unexpected turns
After finishing the project, not too long after that, I got an interview for a Blockchain developer role. It turns out the crypto space really need Rust developers, and because Blockchain projects mostly are just web projects, then my background was matching perfectly. In the interview I was asked about my most advanced project I’ve worked on — it was this, my Asteroids project. And I got the job offer. Probably this was not the only reason, I am quite charismatic as well. But I do believe that personal projects that showcase your skills with some interesting or experimental technologies are a huge bonus.
To keep the piggy back ride going, I applied with the project to the Student Scientific Conference 2021 in Ventspils University of Applied Sciences, where I got the first place in IT field out of all the students. As one of the prizes, I got 20$ in Bitcoin. I’m not really into crypto trading but 3 months after the fact I’ve got extra 10$ for doing nothing. Stonks?