Fluid Rendering with Box2D

This is a technical article about how I implemented the fluid in my game “Invasion of the Liquid Snatchers!” which was my entry for the Week of Awesome 5 gamedev competition.

One of the biggest compliments I’ve received about the game is when people think the fluid simulation is some kind of soft-body physics or a true fluid simulation. But it isn’t!

The simulation is achieved using Box2D doing regular hard-body collisions using lots of little (non-rotating) circle-shaped bodies. The illusion of soft-body particles is achieved in the rendering.

The Rendering Process

Each particle is drawn using a texture of a white circle that is opaque in the center but fades to fully transparent at the circumference:

These are drawn to an RGBA8888 off-screen texture (using a ‘framebuffer’ in OpenGL parlance) and I ‘tint’ to the intended colour of the particle (tinting is something that LibGDX can do out-of-the-box with its default shader).

It is crucial to draw each ball larger than it is represented in Box2D. Physically speaking these balls will not overlap (because it’s a hard-body simulation after all!) yet in the rendering we do need these balls to overlap and blend together.

The blending is non-trivial as there are a few requirements we have to take into account:

  • The RGB colour channels should blend together when particles of different colours overlap.
    • … but we don’t want colours to saturate towards white.
    • … and we don’t want them to darken when we blend with the initially black background colour.
  • The alpha channel should accumulate additively to indicate the ‘strength’ of the liquid at each pixel.

All of that can be achieved in GLES2.0 using this blend technique:

glClearColor(0, 0, 0, 0);

Putting all that together gets us a texture of lots of blurry coloured balls:


Next up, is to contribute this to the main backbuffer as a full-screen quad using a custom shader.

The shader treats the alpha channel of the texture as a ‘potential field’, the higher the value the stronger the field is at that fragment.

The shader compares the strength of the field to a threshold:

  • Where this field strength is strong enough then we will snap the alpha to 1.0 to manifest some liquid.
  • Where the field strength is too weak then we will snap the alpha to 0.0 (or we could just discard the fragment) to avoid drawing anything.

For the final game I went a little further and also included a small window around that threshold to smoothly blend between 0 and 1 in the alpha channel, this softens and effectively anti-aliases the fluid boundary.

Here’s the shader:

varying vec2 v_texCoords;
uniform sampler2D u_texture;

// field values above this are 'inside' the fluid, otherwise we are 'outside'.
const float threshold = 0.6;

// +/- this window around the threshold for a smooth transition around the boundary.
const float window = 0.1;

void main() {
    vec4 col = texture2D(u_texture, v_texCoords);
    float fieldStrength = col.a;
    col.a = smoothstep(threshold - window, threshold + window, fieldStrength);
    gl_FragColor = col;


This gives us a solid edged boundary where pixels are either lit or or not lit by the fluid.
Here is the result after we apply the shader:

Thing are looking a lot more more liquid-like now!

The way this works is that when particles come within close proximity of each other their potential fields start to add up; once the field strength is high enough the shader will start lighting up pixels between the two particles. This gives us the ‘globbing together’ effect which really makes it look like a fluid.

Since the fluid is comprised of thousands of rounded shapes it tends to leave gaps against the straight-edged tilemap. So the full-screen quad is in fact scaled-up to be just a little bit larger than the screen and is draw behind the main scene elements. This helps to ensure that the liquid really fills up any corners and crevices.

Here is the final result:



And that’s all there is for the basic technique behind it!


Extra Niceties

I do a few other subtle tricks which helps to make the fluids feel more believable…

  • Each particle has an age and a current speed. I weight these together into a ‘froth-factor’ value between 0 and 1 that is used to lighten the colour of a particle. This means that younger or faster-moving particles are whiter than older or stationary parts of the fluid. The idea is to allow us to see particles mixing into a larger body of fluid.
  • The stationary ‘wells’ where fluid collects are always a slightly darker shade compared to the fluid particles. This guarantees that we can see the particles ‘mixing’ when they drop into the wells.
  • Magma particles are all different shades of dark red selected randomly at spawn time. This started out as bug where magma and oil particles were being accidentally mixed together but it looked so cool that I decided to make it happen deliberately!
  • When I remove a particle from the simulation it doesn’t just pop out of existence, instead I fade it away. This gets further disguised by the ‘potential field’ shader which makes it look like the fluid drains or shrinks away more naturally. So on the whole the fading is not directly observable.

Performance Optimisations

As mentioned in my post-mortem of the game I had to dedicate some time to make the simulation CPU and Memory performant:

  •  The ‘wells’ that receive the fluid are really just coloured rectangles that “fill up”. They are not simulated. It means I can remove particles from the simulation once they are captured by the wells and just increment the fill-level of the well.
  • If particles slow down below a threshold then they are turned into non-moving static bodies. Statics are not exactly very fluid-like but they perform much better in Box2D than thousands of dynamic bodies because they don’t respond to forces. I also trigger their decay at that point too, so they don’t hang around in this state for long enough for the player to notice.
  • All particles will eventually decay. I set a max lifetime of 20-seconds. This is also to prevent the player from just flooding the level and cheating their way through the game.
  • To keep Java’s Garbage Collector from stalling the gameplay I had to avoid doing memory allocations per-particle where possible. Mainly this is for things like allocating temporary Vector2 objects or Color objects. So I factored these out into singular long-lived instances and just (re)set their state per-particle.

Open-Sourcing Old Projects

I have made the decision to open-source some of my old projects onto Github. These are ones that have not seen any love in a while.

So with no further ado I am excited to announce the open-source debut of 3 such projects:

  • PaprikaLang – A hand-rolled compiler targeting .Net. The Paprika language itself is also an experiment to disguise certain key functional techniques (like reduce/fold and immutability) and present in them more palatable way for the procedurally minded. Paprika has some esoteric syntax that I have not seen all in one language before. Probably at some stage I will write a bigger post about this; (programming) language design has always been an interesting topic for me.
  • GamutOfBlob – My entry for the Gamedev.net Week of Awesome IV competition which won 1st prize. Coded in only a week, so don’t judge the code too harshly 😉
  • GiftStack – Just me messing around with Apache Cordova and OnsenUI to build a simple mobile app. Horribly unfinished but it does demonstrate that I can do the Javascripts when I have to!


So why am I doing this? Really just to show off some of things I’ve done over the years. Why do any of us upload anything to the internet afterall!?

More projects will follow in due course as and when I find the time to excavate them from the darkly depths of old harddrive backups. But I’m pleased that the ball is already rolling!

“Week of Awesome II” – Post-Mortem

Amazingly it has been a whole year since Gamedev.net hosted the first Week of Awesome competition. I competed last year and wrote a post-mortem of my game so it’s that time again! A bunch of people have already written up post-mortems, which is great to see. As far as I recall last year only a couple of us did.

This year the rules were much the same: A theme is announced at the start and 7 days with which to implement that into a playable game.

Last year the theme was about what if dinosaurs were still alive. This year the theme was “The toys are alive!“. I’m beginning to notice a sub-theme going on 😉

You can download my game (with a few bugfixes) here: Save My Toys.zip

Save My Toys!


What follows is my post-mortem, covering how I approached the problem and how I thought it went after-the-fact…


Early Considerations

Before even knowing the theme there are some considerations to make.

  • I am working by myself on this.
  • I am a good programmer (I think) and precious little else – Not an artist, sound designer, level designer… nothing.
  • We have only 7 days available to build/test/polish a game and I have work on 5 of those too.
  • I believe the secret to a good entry is to have a simple idea that is executed well. (The secret to a winning entry might well be a big idea executed well, but that’s something else entirely)
  • When brainstorming ideas it is important to stop and think about how that idea will rack up points from the individual judging criteria. Which include categories like graphics, gameplay, sound, etc.

With these things in mind there is no chance of me making an asset-heavy game. If it requires 3D meshes, skeletal animation, complex sprites, custom sound FX, complex manually-created levels — basically anything like that. It won’t work for me. I am more or less limited to a 2D game with simple, (mostly) static sprites. Last year I got around this by going for a deliberately over-simple MSPaint look and procedurally generated levels, I wanted to try something a bit different this year though.

Additionally it goes (almost) without saying that scope will be a constraining factor here, and feature-creep is an ever-present enemy of any project.

Toy Theme & Brainstorming

The toy-related theme was challenging because it’s not an abstract idea (like “Light vs Dark” say). I concluded that one simply cannot get very far without actually rendering some toys to the screen at some point – and asset production is a major nemesis here.

Being a cutesy theme I wanted some cutesy graphics and was reminded of an artist called Kenny who had posted on GDNet some months prior to tell us all about his free-to-use tilesets that he’d created. I was impressed at the time and quickly hunted them down: http://opengameart.org/users/kenney This guy has done a wonderful thing because are all licensed to Creative Commons Zero which puts them in the Public Domain, as in totally freeballs!

It’s hard to pass up a resource like that, so I very easy settled on the idea of a tile-based game. At this point I brainstormed 3 possible ideas:

  • Sokoban – The idea would be you play as “Mom” or maybe <Insert Generic Child Name Here> tidying away the toys who had up’d and littered themselves around the bedroom during the night.
  • A Rodent’s Revenge variant – Except obviously instead of cat and mouse, the toys would be defending themselves against some kind of enemy (maybe Mom is the enemy?)
  • A Lemmings variant – You control a stream of alive toys who are just trying to get home.

I decided to discard Sokoban. As a core idea it is too simple – I would easily have that game polished in just a few days which would be a waste of the full week. At the same time the prospect of extending the gameplay is daunting. It turns out that the impressive thing about Sokoban is not the gameplay itself, it’s the fact that some poor guy once managed to dream up those devilish maps!

Rodent’s Revenge didn’t really inspire me enough so Lemmings it was! This was always going to be a favourite idea as I have long wanted to make a Lemmings variant.

I began researching for ideas that would be a good fit for a tile-based version. In original Lemmings you assign individual lemmings to specific tasks and they add/remove terrain pixels which alters the flow of those low-res dudes. I had a simpler idea in mind where the Toys are completely self-autonomous and instead you indirectly control them by adding behaviour-altering tiles to the map (like making them jump, turn around, land safely, explode, etc).

I drew my early inspiration from a game called MinimaLemmings; my research indicated that this game has been cloned/re-skinned by others. I didn’t want to clone it but I really liked the core idea of placing jump tiles, so I “borrowed” that and consequently paid homage to them by roughly basing Level 5 “Difficulty Gradient” from their first level. The forces and velocities between my game and theirs aren’t the same, so I was surprised to be able to mimic that level so easily to be honest!


What went well?

Sprites & Animations

Kenny’s tiles are great, not only are they a source of inspiration all on their own (mushrooms!), but they work beautifully in the game. At least I think so, I *am* colour-blind so take that sentiment with a pinch of salt 😉

I drew all the toys and their animation frames myself (and the angled mushrooms). Granted they are very simple but I am no artist so I am pleased with the result. I think the cutesy animations work well with the rest of the game.

Level Design

To some extent, this remains to be seen as they haven’t been extensively play-tested yet. For all I know there are flaws in them. That being said, I am pleased with the number and quality of the levels I managed to produce.

The fact that this year I was making a game which would require manually-crafted levels was a major concern to me all the way through, at least until day 6 when I had managed to put a few together finally. In the end I managed to produce 10 levels in the game, in increasing difficulty, although the early levels are really quite easy and exploit low-hanging fruit in terms of level design.

To help ease level production and mitigate the amount of time spent fixing level design flaws close to crunch time I came up with a file format that could convey the shape of the level straight from a text file – quick, easy and low-tech!

For example, here is level4.txt:

<level name="Hazards can be Hazardous!">
        X . . . . X X X X X X X X .
        # . . . X # # # # # # # # X
        # . . F # . S . . . . . . #
        # . . # # # # # # # . . . #
        # . . . . . . . . . . . . #
        # . . . . . . . . . . . . #
        # # # X X # . X . X X # X #
        # # # # # # . # # # # # # #
        <spawn amount="10" freq="0.5" />
        <blockers available="5" />
        <jumpSingle available="5" />
        <jumpDouble available="5" />
        <jumpLeft available="5" />
        <jumpRight available="5" />

I opted for “convention over configuration” when it came to levels, meaning I could trivially add new levels just by dropping a file called “levelN.txt” (just replace ‘N’ with a consecutive level number) and the game will load to it when appropriate. No need to register the files with the code.

Time Management

Unlike last year I was more or less on top of my time management this year. My minimum viable entry was essentially ready by some point on day 6 so I had a whole day and half to iron out bugs, design levels and apply other polish.

Part of the reason for this was that I had learnt lessons from last year which minimised the amount of time I spent hunting down terminal bugs. I cpy()’d my Vector2’s, I deferred my Box2d deletes and I had last year’s readme to point me in the direction of good sites to find free fonts and sounds!

Building, Packaging & Deployment

On the week prior to the competition I spent a bit of time nailing the build, package and deployment processes. As this was something that very nearly sunk the ship last year since I left it till the last minute.

First I bundled a complete JRE with my game, so no external dependencies for judges to install! Until the promise of a modularised Java 9 comes out the current JRE is still huuuuge so I had to trim it down a tad. Oracle publish a list of optional files and note one big-ass uncompressed JAR that can be compressed. By eyeing it up, I reckon the JRE is still way fatter than I needed but unfortunately Oracle doesn’t permit you to remove anything further for licensing reasons.

I also needed a way to connect my game with that JRE. A batch script would do it but isn’t very pretty so I found a project called Launch4j which creates an .exe that will launch your JAR for a given JRE – perfect!

Finally, LibGDX (the simplistic game framework I was using) has radically changed their build process since I last played with it. They now use a tool called Gradle, which is a coming together of Groovy, Ant and Maven into a single build tool. It’s quite swanky but I am not familiar with it. So I had some tedious “fun” getting all that to work correctly.

By doing all this the week before, I could just focus on the game itself.


What went wrong?

Non-gameplay Screens

Those following my progress updates during the competition would have seen that I posted a few times about getting non-gameplay screens working. My update loop, input handling and rendering were so slapdash that it wasn’t possible for me to handle anything that wasn’t “in-game”. I decided to expend a bunch of time refactoring them to support non-gameplay screens and I ended up re-inventing the old idea of GameStates once again.

Unfortunately I spent so much time doing this that in the end I didn’t have the time to fully exploit the feature. My final game has only 4 states:

  • Start screen
  • Text-based intro screen
  • In-game
  • Text-based end-game screen

Whereas I planned to have highscores and level-selection screens. But hey ho.

The idea and implementation of GameStates is very generic but very useful. I think for next year I will prepare in advance an empty LibGDX project template that includes a GameStates implementation from the beginning.

Box2D is a Physics Engine and will always want to be a Physics Engine!

I coped with this by staying calm. But I know that Box2d is basically a poor choice for the movement controllers in my game.

What I really wanted was:

  • Non-physical horizontal movement but fully-elastic rebound off walls.
  • Gravity (read: physical vertical movement) but completely inelastic landing on floors.
  • Non-physical (but physically “believable”!) jumping movements.
  • Collision detection & resolution (but NOT involving conservation of momentum, etc).

You basically have to fight Box2d to get the non-physical behaviours that you want. On the whole what I want is a colliding kinematic simulation, not a dynamics simulation.

I could probably write one myself, but not in the timeframe of the competition. I decided it would be wiser to fight with Box2d and get the result I wanted.

The magic here basically amounts to tracking velocity yourself outside of Box2d and just keeping the simulation in sync using setLinearVelocity(). Gross but it works.

Additionally, to get completely plastic collision against the ground working well, I had to implement a ContactListener and disregard the contact entirely. To start with I was just detecting the case using the impact normal and calling setLinearVelocity with a zero’d vertical component to remove any bounce, but it was producing visual artifacts (I presume because it was – by necessity – spread across two update cycles with a frame rendered in-between).

Lots of hair-tearing fun to be had all round! Like any framework though, it’s a matter of becoming familiar with its foibles.

My Upload Speed

I always forget how crap my home internet is. It took me 20 – 30 minutes to make an upload. What I should have done is get it all setup on my work PC, remote into it and do the upload from there!

Since I was making incrementally more-finished uploads as the competition drew to a close I ended up losing a couple of hours total just managing my uploads – each one was very tense and I could hardly focus on code while one was going on. I would have liked to churn out a couple more levels, but nevermind.


What got Cut?

With more time I would have extended the player’s tool-set to include one-way barriers and explosives (sacrifice a toy to carve a route through for others in its wake – ala traditional Lemmings blowing up).

I would also have liked to explore the lock-and-key mechanic more. I had different coloured lock and key sprites, which would have been used for more complex puzzle logic. I only managed to make a couple of levels involving these, which doesn’t do it justice really.

I also wanted a level where you have a stream of toys that spawn at a slower frequency and you exploit that to split the stream into two teams which head off in different directions simultaneously.

In-game-help – Like last year I wanted to introduce signposts that would popup helpful tips and comedy relief. Some signposts would be off the critical path and only there for the hard-core players to reach.

Gems – Some kind of collectible that would encourage replay and allow for gauging how good a particular solution was.

Water – I had spikes and water was essentially just another hazard. I had pondered the idea that maybe only the ball and the duck could cross water tiles.

One-way Platforms – Currently solid blocks will block from all directions. But there was an occasional need (that I had to work-around in the level design) for a platform tile that could be passed through from the under-side but would be hard like a floor when landed on.


Final Thoughts

Once again the competition was a load of fun. It eats a week of your life but the result always feels completely worth it.

I have played many/most/all of the other entries and they are impressive to say the least. Those made with Unity are of particular interest because the pace at which those contestants could churn out gameplay was staggering. I think I will have to spend some time getting to grips with Unity at some point – who knows maybe next year’s entry from me could be Unity powered!

It is interesting actually, the shift in technology choices since last year. This time around there were a lot of people using Unity and other engines. Last year there was a high percentage of Java/LibGDX entries, but only 1 or 2 this year. I expect next year will be even bigger and badder as the competition gains visibility and people improve their skillsets.

Since I was using github to keep my codebase in sync between home PC and travelling laptop my code is (and always was!) available online. But I have spent a bit of time today converting my readme to markdown and cleaning up directories, etc. You can find the repo here: https://github.com/daveagill/WoA2

Now it’s all in the hands of the judges.

Good luck to everybody!

On Becoming Engaged!

I am now engaged to my girlfriend-come-fiancée of 5 years!!

We’re very pleased!

I proposed on Thursday October 24th at Anglesey Abbey in their Dahlia garden and successfully managed to conceal the ring in its box for the whole trip until that moment – so it was total surprise to her! 😀

Everybody always asks if I got down on one knee – and I did! Since it makes for a bit of a spectacle I waited until everybody else had gone away first so we could have our moment in private.

I bought the ring online. It’s platinum with a Morganite central stone surrounded by small diamonds and sets of diamonds embedded in the band also. It’s lovely to look at:

Engagement Ring