For my Ludum Dare entry Lonely miner I implemented water simulation.
You can see it in action here:
First you need to know how to use box2d or some other fast physic library that can handle circles. Particle simulator would be best but integrating that to game would take some precious time that I didn’t have. So I created a pool and obstacles and hefty amount of small slippery balls with pretty high density. You don’t want any friction, damping and only small amount of restitution. Radius of one ball is about 0.25m when my full screen size is 48m x 32m.
So this is how things look with debug renderer on this stage.
Simulating lots of dynamic bodies that clamp often to one place is really heavy weight operation. This need to be taken consideration. For this reason I used really inaccurate physic settings. I stepped world with only one velocity and position substeps. Also I fixed physic steps to 30/s.(After competition I noticed 20 would be enough) Always when dealing with fixed time step you want to interpolate or extrapolate position when physic are not stepped but rendering is. I choosed extrapolationing. This is simple to pull of.
RenderPos = PhysicalPos + Velocity * TimeAccumulator
Rendering is the part that trick players to believe that water is not just a bunch of tiny balls. My method was to render water drops as metaballs with radius twice the physical size of the object. Fastest way to make metaball was just sprite that is opaque at middle and fully transparent at edges with smooth circular gradient. I mixed some noise and color there to get better look. Water rendering need two pass. First water is rendered to small off-screen buffer and after that it is rendered as full-screen quad to screen with alpha test discarding too transparent pixels. This will give water hard edges, continuous body and vivid look. To get water drips non circular look just never clear the off-screen buffer completely but leave 75% of alpha channel left but discard alpha if its small enough. Every water drip have unique rotation to give little variety for look. I just ignored body rotation because I don’t want to reveal the circular origin of the water drips.
For final touches I added velocity based color change. This will give nice waves if something collides with water. Its’s also important to render water after ground to get best look. Because water was little too chunky I just colored it to green and called it slime. Lighting and shadow give nice feeling too because water is box2d based and I have implemented open source box2dlights library, integration just worked out of the box. http://code.google.com/p/box2dlights/
Performance is a problem after 500 water drips on desktop and 250 on android but this amount is just as much I need.