How to change colors with a smoothly effect

For the last Ludum Dare, I wanted to have a nice effect on the background of my puzzle game in order to change the color based on the action on the board.

My game is in JavaScript, but except the background property, it should work on other platform too.

So, what do we need ?

First we have to get the initial color (color1) and the new one (color2). In order to change the color smoothly, we will do it with a Timer object.

1
2
3
4
5
6
// définition de la classe
function changeColor(
pElem: js.html.Element,
pInitialColor: RGB,
pEndColor: RGB
){}

Here is the RGB typedef:

1
2
3
4
5
typedef RGB = {
var r : Int;
var g : Int;
var b : Int;
}

The first step is the calculate the distance between those two colors (all methods are based on the RGB type):

1
2
3
4
5
var distance = {
r: Math.round(Math.abs(color1.r - color2.r)),
g: Math.round(Math.abs(color1.g - color2.g)),
b: Math.round(Math.abs(color1.b - color2.b))
}

Now that we have the difference, we have to calculate the value that will determine how the color will change between each step:

1
2
3
4
5
6
7
8
9
var incR = Std.int( Math.abs( Math.floor(distance.r / INCREMENT_VALUE) ) );
var incG = Std.int( Math.abs( Math.floor(distance.g / INCREMENT_VALUE) ) );
var incB = Std.int( Math.abs( Math.floor(distance.b / INCREMENT_VALUE) ) );

var increment = {
r: incR == 0 ? 1 : incR,
g: incG == 0 ? 1 : incG,
b: incB == 0 ? 1 : incB
};

The INCREMENT_VALUE value allows use to determine how we want the effect to change. The higher the value is, the quicker the effect will be.

I’ve set it to 100.

Now we have to calculate the new color :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
if (color1.r > color2.r)
{
color1.r -= increment.r;
if (color1.r <= color2.r) // if we've reach the right color
increment.r = 0;
}
else
{
color1.r += increment.r;
if (color1.r >= color2.r) // if we've reach the right color
increment.r = 0;
}

And same thing for each tone.

I’ll now add this step to the Timer object.

I’m using the Timer class in order to have a cross platform method. But you can use any kind of listener or Signal.

1
2
3
4
5
var timer = new haxe.Timer(Math.round(1000 / (INCREMENT_VALUE/2)))
timer.run = function()
{
// [...]
}

In this loop, you’ll have to change the property of your object.

For example in JavaScript you’ll have :

1
pElem.style.background = rgb2hex(currentColor);

Where rgb2hex transform the RGB object in hexa :

1
2
3
4
5
6
7
private static function rgb2hex(color: RGB): String
{
return "#" +
StringTools.hex(color.r, 2) +
StringTools.hex(color.g, 2) +
StringTools.hex(color.b, 2);
}

Here is an example :