The other day I set out to make a quick way to eliminate the need for sprites when rendering very simple entities with ImpactJS. For example the particle effects, paddles and puck in PiSpace. These entities are now rendered using direct canvas methods and constructed on the fly from input verticies. This allows for a more dynamic nature in the game and much better performance with Box2D v2.1a. More on that in a later post.

Along with using raw verticies to render the objects, I wanted to be able to change the color on any entity in the game based on different conditions. Also, I wanted to produce a smooth gradient fade effect between any set of input colors. A direct example of this in PiSpace is the “HEAT” bar that changes from Green -> Yellow -> Red dependent on how long you have used your boost. Previously, in order to obtain the color fading I would like I used the ImpactJS sprite animation engine to select a frame from a supplied asset. This required that I have an art asset that had a frame with the color I wanted to use available for each effect I wanted to create. I am not much an artist, so my asset pipeline is slow moving for these types of things. Fading from green to red is boring and bland, but throw yellow in there and you get a more interesting effect. So, I put together a color-picker.js plugin for ImpactJS that allows me to quickly generate an array of colors in any gradient combination that I want. Click here for a demo. Below is a sample of a few different combinations:

color-select-sample

To generate the color maps above I used the JavaScript prototype construct to build a ColorPicker object with the following functions:

genMultiHexArray Supply an input array with any number of hex colors and the number of steps you desire between two colors. This will return array with ‘steps’ entries between each sequential pair of colors in the input array. Very useful for creating custom multi-color colormaps.

genHexArray Supply two hex colors and a number of steps. This will return array with ‘steps’ entries fading from color 1 to color 2.

pickHex Supply two hex colors and a ratio. This will return a color that is equivalent to that fade between those two colors at the ratio point.

A few utility functions that are helpful for browser compatibility and the such: hexToRGBstr will convert the hex code to a rgb( r, g, b ) string. hexToRGBA will convert the hex code to a rgb( r, g, b, a) string with a default alpha set to 1. frontPad will check the length of the hex string to ensure that there are the necessary leading zeros.

Using this method has greatly improved my asset pipeline speed and greatly improved the performance on my games.

The ImpactJS plugin version of this code can be found on GitHub. Here is the complete stand-alone object code:

/*
genMultiHexArray will take an input array of any number of hex colors
and the number of steps to create a smooth gradient fade between the
colors in sequence.

Example: input = [0x00FF00, 0xFFFF00, 0xFF0000] with steps = 10
will produce a Green to Yellow to Red gradient with 10 steps between
each source color. Total of 23 color codes.
*/
ColorPicker.prototype.genMultiHexArray = function(input, steps) {
var multiColor = new Array;

// Find each sequential pair to compare
for (var i = 0; i < input.length - 1; i++) {
// Set hex colors
var hc1 = input[i];
var hc2 = input[i + 1];

// Save first color
multiColor.push(hc1.toString(16));

// Break hc1 into RGB components
var r = hc1 >> 16;
var g = hc1 >> 8 & 0xFF;
var b = hc1 & 0xFF;

// Determine RGB differences between hc1 and hc2
var rd = (hc2 >> 16) - r;
var gd = (hc2 >> 8 & 0xFF) - g;
var bd = (hc2 & 0xFF) - b;

// Determine new colors
for (var j = 1; j < steps; j++) {
// Where are we on the gradient?
var ratio = j / steps;
// Calculate new color and add it to the array
multiColor.push(((r + rd * ratio) << 16 | (g + gd * ratio) << 8 | (b + bd * ratio)).toString(16));
}
}

// Add the last color to the end of the array.
multiColor.push(input[input.length - 1].toString(16));

// Test that all hex color codes are properly front loaded
for (var k = 0; k < multiColor.length; k++) {
while (multiColor[k].length < 6) {
multiColor[k] = '0' + multiColor[k];
}
}

// Return the new array of colors.
return multiColor;
};

// function will return an array with [r,g,b,a] set to
// appropriate values.
ColorPicker.prototype.hexToRGBA = function(hex) {
// Break hc1 into RGB components
var d = new Array;
// R
d[0] = parseInt(hex.substring(0, 2), 16);
// G
d[1] = parseInt(hex.substring(2, 4), 16);
// B
d[2] = parseInt(hex.substring(4, 6), 16);
// Alpha
d[3] = 255;

return d;
};

// Function will return a 'rgb( r,g,b )' string set to the
// appropriate values.
ColorPicker.prototype.hexToRGBstr = function(hex) {
// Break hc1 into RGB components
return "rgb( " + parseInt(hex.substring(0, 2), 16) + ", " + parseInt(hex.substring(2, 4), 16) + ", " + parseInt(hex.substring(4, 6), 16) + " )";
};

// Useful for checking front padding of a hex color code
ColorPicker.prototype.frontPad = function(hex) {
while (hex.length < 6) {
hex = '0' + hex;
}
return hex;
};


And if you are interested, here is the code I used to generate the demo images above:

// Initialize ColorPicker object
var picker = new ColorPicker;

// Generate and draw fade between White and Black with 400 steps
var fade = picker.genHexArray(0xFFFFFF, 0x000000, 400);
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
drawBoxes(ctx, fade, "Two Color Fade");

// Generate the Matlab Jet colormap with 80 steps between each color
// then render
var jet = picker.genMultiHexArray([0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0x000000], 80);
var c2 = document.getElementById("canvas2");
var ctx2 = c2.getContext("2d");
drawBoxes(ctx2, jet, "Matlab Jet");

// Generate the Matlab HSV colormap with 70 steps between each color
// then render
var hsv = picker.genMultiHexArray([0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0x000000], 70);
var c3 = document.getElementById("canvas3");
var ctx3 = c3.getContext("2d");
drawBoxes(ctx3, hsv, "Matlab HSV");

// Regenerate the Matlab HSV colormap in a higher resolution with
// 27,000 steps between each color.
// Use the createImageData method to quickly render the colormap
// with each entry in the array represneted by a single pixel.
var pix = picker.genMultiHexArray([0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0x000000], 27000);
var c4 = document.getElementById("canvas4");
var ctx4 = c4.getContext("2d");
drawPixels(ctx4, pix, picker, "Matlab HSV HighRes");