Nolla Games kindly talked about the technical decisions behind their game Noita with fascinating mechanics and an endless amount of simulated pixels.
Hi, my name is Petri Purho. I’m one of the 3 developers of Noita. The other two are Olli Harjola (developed The Swapper) and Arvi Teikari (Baba Is You and a hundred of other games). And I worked on Crayon Physics Deluxe previously.
We have a studio called Nolla Games and we’re based in Helsinki. The three of us have worked on our separate projects before and we teamed up to create Noita. We’ve been working on Noita for a while, but the company itself was formed in 2016.
Material System Mechanics
The game is based on a falling sand style simulation. Essentially, it’s complex cellular automata. Every pixel in the game follows rather simple rules, but when you combine them together you get surprising and unexpected results.
For example, liquid pixels first check if they can go down. If not, they check left and right to see if they can move that way. With those rules, you get a rudimentary 2D liquid. To make liquids have different densities you just compare the densities when figuring out if you can go down (and then swap the pixels).
The fire is kind of simple as well. When something is on fire it will look in a random direction to see if it can ignite that pixel. Oil is flammable, but water is not so the fire will spread in the oil, but stop when it hits the water. If the fire tries to ignite the water it will convert into steam instead.
For gases (like steam), you can think of the rules as for the inverted water. First, you check if you can go up – if so, move that way. If not, check if you can move left or right.
The wood that burns is easy, you don’t really do anything. If set on fire, you wait until the fire has been burning long enough and then you destroy that pixel.
The rules are in practice a bit more complicated, but that’s the basic logic.
Explosions & Collapses
We have several materials that stick to the ceiling and fall infrequently, but most of the materials that are static like stone don’t have those rules applied. So what we do is that when there’s an explosion large enough we look at the pixels that the explosion collided with. If they happen to be “good candidates”, we will turn those into collapsing sand materials.
Then, we also have rigid bodies in the game. Each pixel in a rigid body knows that it belongs to that rigid body and location inside that rigid body. So when a rigid body is updated, the pixel gets its position that way. If a pixel that belongs to a rigid body gets destroyed, the simulation recalculates the shape for the rigid body (or rigid bodies if the shape is now cut in two or more pieces).
To make chunks fall down, we do what we did with the falling pixels, but in this case, we do it with rigid bodies. We look for a good place to collapse things and then try to figure if we can carve out shapes. If we can then we create rigid bodies out of those materials and let them fall.
Procedural Generation of the World
The world is procedurally generated, but we do have an overall structure that stays the same, mostly to give the game good pacing and for us to control how the game plays. The basic structure of the world is the following: there is the first area (mines) and underneath that, there’s the second area, and so forth.
We can’t say what’s at the very bottom as it’s a bit spoilery, but technically, the engine does allow you to go very very very deep. We had a few infinite fall moments during the development.
We tried a few different ways of doing procedural generation. At the moment, we use a few different techniques, but the main part of it uses Sean Barrett’s Herringbone Wang Tiles. Essentially, we have a series of pre-made pieces that are like bricks. They’re laid together in a Herringbone pattern. The Herringbone pattern disguises the edge of the pieces better than the usual square pieces in which you can easily see the “seam”. Within those pieces, we further randomize things, like with a 50% of putting a random enemy here, a random item there and so forth. We’ve been pretty happy with how well the technique works for a game because it allows us to have quite a bit of control on how things are laid out and still generates a lot of new and varied situations.
The wand system allows the players to modify and create their own spells. The way it works is that you as the player find the randomly generated wands all around the world. Then, in between each area, you get to modify those wands.
The system was inspired by the deck building games like Donald X. Vaccarino’s Dominion. When the player modifies the wands they get to move the spells around between the wands, much like the cards in a deck building game. When the player shoots their wand it draws up the “cards” from the wand and applies the effects. It sounds easy in theory, but in practice, it creates a lot of interesting situations and combinations.
There are a few slow reaction things in our game. We have grass that slowly grows on top of the soil. There’s also moss that slowly grows on еру rocks. The water freezes. Snow melts. The corpses decompose.
They’re all really cool, but when you’re playing the game you rarely notice them. So we haven’t really spent too much time on adding stuff like that into the game.
Optimization of the Falling Sand Simulation
We’ve kept performance in mind during all the development. We use profiling tools to know how much time the stuff is taking and catch early on if something is taking too many precious CPU cycles.
There are a few techniques we use to keep the updating of the world at a reasonable pace. This goes a bit deeper into the falling sand simulation. In order to make the falling sand simulation work, you have to update the world from the bottom up. The reason is that if you don’t do that only the pixels at the very bottom will fall down. The next frame, the pixels above those will move down and so forth. But if you update it from the bottom up, the sequence of the falling rows will be consistent.
Now, having to update the whole world in order to make the falling sand simulation is a really bad fit for multi-threading. The way that’s been solved in Noita is that the world is divided into tinier 64×64 chunks. Each chunk keeps a dirty rect to indicate which pixels need to be updated. So when something is moving in a chunk it marks itself to be updated. This divides the dirty rect into a bunch of tinier dirty rects and those pixels are iterated over. Which is already a huge benefit because it cuts down on the number of pixels to update. But if you were to just naively multi-thread those chunks, some problems would occur when there’s a pixel that leaves its 64×64 area and wanders into the range of another chunk. You don’t want to update the pixel multiple times, so you can just add a counter that says “I’ve been updated this frame, so don’t update me if the frame is the same”. But then you’d have to add atomics or locks to make sure that the value is up to date on all threads. And that would slow things down a lot.
The way we’ve solved this problem is to update the world in a checker pattern of sorts. We do this 4 times. In the first round, we pick every other 64×64 chunk, and the pixels inside the chunks are allowed to move within that 64×64 area plus 32 pixels in each cardinal direction. That creates little crosses. This ensures that every pixel inside that area is only updated by that thread. Then we do this 4 times. That way every thread can safely update everything inside it, and we don’t worry that other threads are accessing their pixels.
Right now, we’re focusing on getting the game into early access on PC. We don’t have a release date yet, but it will be available on Steam once it’s out.