'Fire' visual effect in JavaScript
The fire you're seeing above is a cool visual effect that was hot in the 1990s (pun intended).
It still looks great today and with very simple math and only about 20 lines of JavaScript, it's a great coding exercise.
In a nutshell, we create an array (matrix) of tiles. The higher the value of the tile, the brighter its color. In each animation frame, we randomize the tiles in the lowest visible row and for all the remaining tiles, we calculate their value based on the tiles below. More specifically, we first add the values of the three tiles immediately below and one tile two rows down:
X is the tile being calculated and 1,2,3 and 4 are the tiles whose values are included in the calculation. Next, we divide the sum of the four tiles by a value slightly higher than 4, for example 4.1. This is what makes the flames die out as they go up.
We'll redraw all the tiles in each frame. To do this, we have to convert the array index value into screen coordinates. Because JS does not have 2-dimensional arrays, this conversion is a bit cumbersome.
Here are the tiles' indexes with an example array of 5 columns and 6 rows. The first tile is in the bottom left corner:
The lowest row (elements 0-4) will always be empty.
The tiles in the second row from the bottom (elements 5-9) will be randomized in every frame to keep the fire going.
All the other rows (elements 10-29) will be calculated.
Here is the code with some more explanations. Enjoy!
<html> |
<body style='background-color:black'> |
<canvas id="myCanvas" width="1000" height="800"></canvas><br> |
|
<script> |
const height=80; // number of rows |
const width=100; // number of columns |
let fire=new Array(width * height).fill(0); // declare and reset the array that holds the value of all the tiles |
|
let context = document.getElementById('myCanvas').getContext('2d'); |
window.requestAnimationFrame(burn); |
|
function burn() { |
for(let i=0; i<width; i++) |
fire[i+width]=Math.random()*255; // randomize the 2nd row from the bottom |
|
for(let y=height; y>1; y--) // every row |
for(let x=0; x<width; x++) { // every column |
let i=y*width+x; // convert the x and y coordinates to the array index |
fire[i]=Math.floor(( // add the cell values: |
fire[(y-1)*width+ (x-1+width)%width]+ // below, left |
fire[(y-1)*width+ (x +width)%width]+ // immediately below |
fire[(y-1)*width+ (x+1+width)%width]+ // below, right |
fire[(y-2)*width+ (x +width)%width] // two rows below |
)/4.04);} // division to lower the value as the fire goes up |
|
for(let i=width*4; i<width*height; i++) { // now we're drawing the fire on the screen |
context.beginPath(); // convert the index value i to screen coordinates and draw a box |
context.rect((i%width)*10, (height-Math.floor(i/width))*10, 10, 10); |
context.fillStyle ='rgb(' + fire[i]+ ',0,0)'; // the red component of the RGB color is the value of the cell. |
context.fill(); |
} |
window.requestAnimationFrame(burn); |
} |
|
</script> |
</body> |
</html> |
Check out these programming tutorials:
Domino effect in Blender Python
Wrecking ball effect in Blender Python
3d fractal in Blender Python
Fractals in Excel
Your first program in JavaScript: you need 5 minutes and a notepad
Animated fractal in 32 lines of Javascript
Tutorial - interactive, animated sprites in JavaScript
PS. Many thanks to
/u/inu-no-policemen for some great improvements to the code!