I had a little bit of time today to do some me-coding (as opposed to work-coding), so I knocked up a quick 90’s era 2D fire effect. I’d actually written it C++ and OpenGL the other week and was meaning to transfer it into WebGL so it can run live rather than having a captured video, but my WebGL kung-fu is pretty weak at the moment so just to get it done I translated it to Flash.
How it works
The effect itself is incredibly simple, as the video below explains. You randomly add “hot-spots” to the bottom of the pixel array, then the new temperature value for a pixel is just the average of the pixel and the 3 pixels below it with a small amount subtracted so that the flames “cool”, which you then map to a colour gradient.
In the OpenGL version I’d made the colours for the flames into a 1D texture which can be easily interpolated, but I had to find some functions to do that in AS3 as there don’t appear to be 1D textures! Also, getting and converting the colours from uints and hex-codes and stuff was a pain – but I finally nailed it after googling around and pulling functions from various places (referenced in the source).
I think the most important thing I learnt from getting this working in Flash was how to and how NOT to convert colours from uints into red/green/blue components. For example, a lot of code online will use a function like the following to convert red/green/blue values into a 24-bit uint:
function rgbToUint(red:uint, green:uint, blue:uint):uint
var hex = "0x" + red.toString(16) + green.toString(16) + blue.toString(16);
The above function looks like it works, and in fact in most cases does work – but if you get single digit values they aren’t zero-padded properly and craziness ensues!
The correct way to convert RGB to uint is by using the two functions below which ensure that values are capped AND zero-padded as appropriate, which means that everything works under all possible conditions:
if (hex > 255)
hex = 255;
//trace("hex val overloaded");
var hexStr:String = hex.toString(16);
if (hexStr.length < 2)
hexStr = "0" + hexStr;
function getHexColourFromRGB(r:uint, g:uint, b:uint):uint
var hexStr:String = convertChannelToHexStr(r);
hexStr += convertChannelToHexStr(g);
hexStr += convertChannelToHexStr(b);
var strLength = hexStr.length;
if (strLength < 6)
for (var j:uint; j < (6-strLength); j++)
hexStr += "0";
var finalStr = "0x" + hexStr;
Overall, it’s a nice simple effect – but it’s pretty CPU intensive. In the above example I’m only using a stage size of 250px by 120px and the framerate takes a hit even then.
I could use a single loop instead of embedded x and y loops, and I could manipulate more colours directly as uints rather than pulling out the RGB components, but it’s prolly not going to improve more than about 10-15%. As usual, there’s source code after the jump, so if you have a play with it and manage to speed it up a bunch, feel free to let me know how you did it!
Download Link: 2D-Fire-Effect.fla (Flash CS4 fla – but CS5 and later will convert on load).