I’ll go over most of these in a separate post but one element seemed to deserve a post of it’s own – smoke.
I wanted to add smoke as a way of increasing a sense of ‘permanence’ to the combat. Explosions are over and done in less than a second but smoke could hang around for ten seconds or so and build up depending on how much destruction is going on.
I wasn’t after a ‘realistic’ smoke effect but something more stylised to fit in with the rest of the game art. It seemed logical to use circles as the base for the effect but I felt pretty sure I’d want these circles to increase in size over time, maybe quite dramatically, so I didn’t want to rely on scaling sprites for this. I decided to use custom shaders instead as this should give me much more control.
So the first step was to use a custom shader to draw a simple filled circle. Initially I thought the geometry behind this would be quite complex but, in fact, it’s just simple pythagoras. Here’s the approach in pseudo code…
float x = 0.5-coords.x;
float y = 0.5-coords.y;
// fill the entire space
float radius = 0.5;
if ( x*x + y*y <= radius*radius )
{
// return a color
}
else
{
// discard
}
…I’d be lying if I said I got to this stage quickly though! Though it didn’t take me long to figure out the maths, I spent far too long passing the shader a region of a texture to draw rather than the entire texture and getting confused as to why my results were all off (forgetting that coords.x and coords.y are relative to the entire texture to be drawn, not the region). When I started passing a simple 2×2 image to the texture everything clicked into place.
Once I’d successfully drawn a filled circle it was pretty easy to expand that technique to draw concentric rings and the like, and to animate these by basing their radii on parameters that are passed to the shader and change each frame.
Next step was to find a way of applying motion to these circles that looked suitably smoke-like. I started by simple applying a uniform velocity to several circles distributed across a certain range, e.g. -60d to +60d, as well as increasing the circles size over time.
When I finally got this to work the way I intended it didn’t look too bad as a starting point so I added a couple more parameters to make things more interesting – a ‘deceleration’ parameter (so that the velocity of the circles decayed over time), and a ‘buoyancy’ parameter (so that the circles gradually floated upwards over time). I also decreased the opacity of the circles over time so that they gradually faded out.
This looked much better but the results were still far too uniform, forming very obvious geometric patterns as the circles intersected. To stop this I added a certain amount of randomisation to both the circles initial velocity and their ‘buoyancy’ – this produced a much more smoke-like effect – still stylised but not overly ‘geometric’.
I was almost there now but felt that the smoke cloud was dissipating too quickly and lacked some kind of ‘weight’ to it’s centre. I fixed this by adding additional batches of circles with a decreasing initial spread and velocity with the final one staying pretty much in the same place. This looked a lot better.
Lastly I experimented with adding pixelation to the shader so that the circles were drawn at the ‘game’ pixel resolution rather than the ‘screen’ pixel resolution. Unfortunately I felt this looked pretty crappy – one of those things that ‘should’ have worked but didn’t! So I left things as they were but I did add a gradually increasing amount of pixelation over time so that when the circles have pretty much faded out they kind of ‘dissolve’ out rather than just disappearing.
Actually I couldn’t stop there – I thought the centre of the smoke cloud looked too ‘solid’ to start with so added a small particle effect to imitate ash or something. It’s subtle but it just breaks things up a little.
I’m pretty happy with the final result – watch this space for a mini-tutorial on using shaders to draw geometric shapes. I think I might end up using that technique again in this game…
Dev Time: 1.5 days
Total Dev Time: approx 97.5 days
2 Trackbacks
[…] using a custom shader. Luckily I was able to re-use the ‘smoke’ shader I talked about here. I may tweak this some more but am pretty happy with it as […]
[…] art style and was also causing a few performance issues on some machines. You can see the effect here (I usually turn this off for recording GIFs as it overloads the GIF […]