Slow Rush Studios logo,
    depicting an apprehensive-looking snail rushing forward

Slow Rush Studios

◂  Making Atoms Kinetic
News index
Playing Nice with Moving Bodies  ▸

Particles, for real this time

Contents

This week I had a second shot at implementing particles, which are my planned solution for stopping atoms from crushing moving bodies (so that dropping sand on a box doesn't cause the box to flip out).

And this time it worked! Or at least, the particle implementation worked. And I added a neat time travel debugging feature to help figure out why the rest of things weren't working.

Plan recap

For those who missed last week, the idea was that when (e.g.) a moving box overlaps with an atom then the atom gets wrapped into a "particle", and we fling it into the air (with wild abandon).

The trick is that particles won't be allowed to collide with themselves or with moving boxes, so they should be able to get out of the way of the box ASAP.

Making it actually work

Last time, I got way too hung up on making particles find the perfect position: I tried moving them backwards incrementally, tried having them bounce, tried having them not overlap with each other, etc.

So this week I started off with a dead simple approach: when a particle hits an atom, search upwards to find a free spot (and as it goes upwards, also start checking spots either side, meaning it effectively checks a 90 degree arc above the particle), then turn into an atom there.

Animation showing particles turning into pixels once they find a free spot above their contact point
Particles are drawn as circles (atoms are square pixels) here so you can see the difference

It wasn't perfect: when one particle touches an atom of the grey fixed platform then it causes a chain reaction where they all warp to a free spot. But in practice we probably won't have large blobs of particles sticking together like that in the real game, so the chain reaction shouldn't be an issue.

Aside: Sand pixels sometimes also leave gaps instead of falling down properly, which is a problem with my sleeping logic. I'll save that story for another time!

Making it slightly more robust

Now that was working okay but if 2 particles get flung upwards and hit the roof or a wall, one of the particles might potentially tunnel upwards through it and end up on the "floor" above. If the floor is covered in a flammable liquid and the particle can ignite flammable liquids... well I haven't implemented those things yet but that would be a pretty bad bug.

So I had a second go at having the particle look back along its reverse velocity to find a landing spot:

Animation showing particles turning into pixels along the vector that is the reverse of their velocity
This is a different animation from the last one, I swear

Okay, you can't tell it's actually working: velocity is down (thanks gravity), so reverse velocity is "up" - meaning the effective behavior is the same as before.

So let's try a before and after, where I fire the particles off to the upper-right and they hit the ceiling:

Before: particles search upwards for a landing place
After: particles search for a landing place along their reversed velocity

It's kind of better! At least the particles are working as expected and not going through walls when they turn into atoms.

This was much easier to implement than last time because I totally punted on the hard part: if we can't find a landing spot for the particle, then instead of having it move backwards along its reverse velocity and bounce off atoms until it finds a spot (as I tried to implement last time), it just gets destroyed. It's not accurate, but having an atom mysteriously appear far away from where the particle initially hit something would feel weird too.

On the other hand, once the particles turn into atoms, you can see some atoms getting blown off to the right, as if by a wind. Unfortunately, I haven't implemented any wind yet. So kinetic atom movement code still needs some work!

Rewinding time

Figuring out where particle or atom movement logic is going wrong was often difficult because - by the very nature of bad movement - it's hard to predict exactly when it's going to go wrong: a particle or atom makes a move in a way that feels off, but I couldn't remember what the arrangement of atoms was that caused that weird movement (so it was hard to make a minimally reproducible test case to play with).

So I added the ability to rewind time so the game runs backwards:

I can press [ and ] to step the game backwards and forwards

Internally this is implemented in the simplest way possible: copy the entire game state after each update, and keep the last 30 seconds worth of updates. I already had game state separate from all state related to rendering (drawing), so it wasn't too tricky to do.

However, it is quite memory intensive: it uses about a gigabyte of memory every 5 seconds (~3mb per update x 60 updates per second x 5 seconds = almost a gigabyte!), so for the web demo you can only go back 3 seconds (web assembly, the intermediate language which the web build gets compiled to, seems to only support something like 4gb of memory).

Aside: A "cleverer" implementation would use structural sharing so that copies can reuse bits of previous game state if that game state hasn't changed - but this is only a debug tool and I have 64gb of memory in my desktop so it's not worth it.

This implementation seems useful already but it's also limited:

Actually using this thing to diagnose and fix the broken atom movement will have to wait till next week!

Playable but fairly broken web demo‎

Here, you can create some particles, and play with the velocity (see UI on top right) too.

But before you go, I need to warn you: if you hold down left mouse button to draw a continuous chunk of particles, you'll actually be creating 60 particles per second multiplied by your brush size (since particles can overlap with each other), and when the very first one touches an atom, it'll trigger a chain reaction where they all turn into atoms. Again, that shouldn't happen in the actual game because I won't be spawning a ton of particles all close to (or overlapping) each other.

Tip: If you want to draw particles right next to each other, pause the game (P) first: your brush will check to see if there's a particle exactly at the given position, but if the particles have moved slightly due to gravity then that check gets bypassed*).

Particles are drawn as circles in this demo:

Click to focus, then play with keyboard and mouse. No mobile support! Give feedback.

W & A/D to jump & move, and you can find most of the other controls by hovering over the buttons in the UI.

New good things:

New bad things (exposed by firing particles/atoms with velocity, or caused by other not-finished-yet work):

So in short, I implemented a thing, which exposed a bunch of other broken things, so the overall result looks way worse than before. And the other stuff I worked on is still half-baked and making it worse. That, my friends, that's progress, right there.


*: I could fix the "stop drawing overlapping particles with the brush" check properly (so that you don't have to pause), but it's actually useful for testing purposes to be able to make a bunch of particles overlap.

◂  Making Atoms Kinetic
News index
Playing Nice with Moving Bodies  ▸