I have participated in LudumDare two times before. I used Rust to make all those games.
- lifeshot – agar.io-like game where you shoot with your own health. Also with a multiplayer post-jam version lifeshot.io (unfinished, kind of abandoned)
- egg-farm – this is my best so far. It is an ultra hardcore puzzle bullet hell farming simulator 🙂
This time we decided to do it together with my brother. He also participated once in LudumDare, using Unity game engine (“Circle Fight”). He almost didn’t have any experience with Rust before, he just started learning it. All he did is reading the Rust Programming Language book, coding a Rust version of Fluid Simulation for Dummies (translated from C++) as well as making a couple tiny changes to lifeshot.io code.
We also decided to try make a multiplayer game. A couple days before the jam started, we made a small project skeleton containing basic multiplayer movement in grid-based world. To make it as simple as possible, we were going to do something not realtime (to not implement any prediction of player’s movement and such) – the final game runs the server at 2 ticks per second. Unfortunately that, combined with grid-based approach (and very high ping for some people), resulted in not very pleasant movement experience.
Before the jam started, there was a vote for the theme. A week before the start, there were 16 themes selected to vote for:
- Control the world, not the player
- Stuck in a loop
- Feeding the monster
- Delay the inevitable
- Contain it
- Day and night
- You can’t save them all
- Death is not the end
- The world changes when you are not looking
So we decided to have a look at all of them and think of a game that was going to match as many of them as we could. So we came up with the idea of the island.
The first theme we thought about was “The world changes when you are not looking”, so we thought of creating a world where player has limited vision, and the environment is regenerating outside of it. The “day and night” theme suggested we made the vision range bigger during day and smaller at night (potentially only regenerating the world at night). The “shipwrecked” and “nomad” themes were why we decided to make an island.
The announced theme turned out to be “stuck in a loop”. This one we did not spend much time thinking about, so we needed to come up with an way of incorporating it in the game. Basically, the final idea was that the player should try to escape the island by crafting and riding a raft, only to realise that it’s not possible: the world is looped – when you reach one end of the world, you appear on the opposite side, returning back to the island.
So, to create a raft we needed some crafting mechanics in the game. We were trying to make it as simple as possible, so we took inspiration from One Hour One Life – you can hold one item in your hand, and you can combine it with one item on the ground, resulting in optionally an item in the hand, and maybe an item on the ground. For example, to make an axe, you need to combine a stick with a sharp stone. The recipe for the raft is to combine two planks on a water tile.
Splitting the programming
Since we are both programmers we needed to split the code in a way that we don’t work on the same thing.
So, my brother did the server logic since it is not depending on any external libraries. Here’s what he says:
When the theme was announced we had a simple island with a couple trees and randomly moving players. Not really knowing what exactly we were going to make, I started making the things we thought would match any theme. The first thing I did was limited view and generating objects only outside of it. Next, I made it so players could move towards the tile they clicked on, added sticks and pebbles to generation, made them traversable, allowed players to pick and drop items on neighboring tiles.
After all that, I made possibly the most important part of the game – the recipes. Their structure is very simple. The first part is ingredients, which are an item in hand and an item on the ground. The second part is the result, which is identical (item in hand, item on ground). In code making new recipes looks similar to that:
Stick + SharpStone = Axe + None, or
Axe + Tree = Axe + Log. With that done, I added a couple recipes (Axe, breaking a Tree to get a Log, Campfire). This was done on the first day.
On the second and third days I added more items and recipes, split the world into several biomes and made a couple sound events.
Since this is basically first time writing Rust, here’s one problem I encountered: when writing a method that is mutating some fields a structure, Rust makes me write
&mut self, basically borrowing the whole structure, so sometimes I had to inline the code instead of putting it into a separate method.
I think he did pretty well implementing everything we needed for the jam. No help was needed, so I could focus on rendering part.
The rendering is made with my own “game engine”
geng, if you can even call it a game engine. It allows running both on native and WebAssembly targets, so trying out the game is as simple as visiting the website. I would not recommend my engine to other people, as I only use it because it is the only thing I know. There are now quite a few game engines in Rust you can use. The reason for creating my own was that at the time nothing I tried worked with WebAssembly (you could only use emscripten with nightly rust back then). And I like reinventing the wheel. 🙂 I was also just learning the language: my first project was called
ugli – a safe (hopefully) OpenGL/WebGL wrapper (only for things I need), similar to
glium, since I could not understand glium’s (or any Rust) code at all at the time. 🙂
ugli is still used for rendering in
geng (I need to make some higher level abstractions for rendering).
There is also asset loading, networking module that makes working with WebSockets same on native and wasm targets (I’m not sure if there is such a library currently), and my experiments with creating UI (in this game you can see a volume slider in bottom right corner).
Also, there is no entity component system involved (my brain refuses to work with them for some reason).
So yeah, the engine is not worth your time, go use something else 🙂 Bevy looks like a good choice to me.
Art and sound
One of the other things I tried for the first time this jam is making the game 3D, not 2D like before. The only problem is that I have almost never touched 3D editing software before. So this is basically the first time I finally learned some basic Blender. I did not do any texturing, just applied different colors to different polygons.
The sounds for the game were recorded with my own mouth and a microphone, and the for the music I quickly recorded a few chords with the guitar.
Basically, same as with the mechanics, I tried to make them as simple as possible. Hopefully it ended up not too bad. I think I might even like it actually. 🙂
Play & Rate phase
After the game is submitted, the “play and rate” phase of the jam begins. Basically, you need to check out and rate other people’s games to get people to check out yours.
I have decided to do this on stream. To help with that, as another exercise with Rust, my brother created a twitch bot handling people’s submissions, maintaining a queue of games to play. We did have to fix a couple of things on stream, but it worked great.
There are just so many great games created this jam. You are always amazed by how much work people can do in just 72 hours.
So, overall we liked our game a lot. We think it has a lot of potential, so we will work more on it, improving the mechanics and adding more content.
We should definitely get rid of the grid, at least for movement. Maybe we should make the world infinite? Maybe add dungeons and PVE mechanics.
My personal wish would be to be able to go higher in the sky, using some kind of an airship to get an overview of the world 🙂
Game jams are super fun. We did not get high ratings, but anyway, we did something, and we are proud of what we’ve done. See you next LudumDare. Thanks for reading 🙂