# Reduce an X/Y Value to an Index In a 1D array and Return the Array Value

Initially, this is not an attempt at early optimization, though it's thoroughly possible I'm looking in the wrong place :).

The following function returns a height value for aliased columns in a kind of voxel-style height-map renderer.

It is called many, many times for both AI and player controlled entities and used for collision detection. It is not being called unnecessarily, by any entities that are static by nature. So, it's really a question of whether there are any tricky operations I'm missing that could allow the interpreter to better JIT-compile my code.

Please assume that 'mapcol' is an array of [0,255] Numbers with a length of mapscalex*mapscalez. The map dimensions may actually be quite a bit bigger than is suggested here; relevant only because I think any memoization would flood RAM.

I've made my best attempt to sanitize this code for brevity. It naturally references variables that are necessarily augmented on level-load, here represented as simple globals.

var mapscalex = 256;
var mapscalez = 256;
var tilescale = 16;
var tilescaley = 4;

//Returns the Y value for a pair of X/Zs
function getmapheight(x,z){
//Drop the coordinate to the map scale
x = x/tilescale;
z = z/tilescale;

//Clamp the coordinate to the map dims
x = Math.min(mapscalex-1,Math.max(0,Math.floor(x)));
z = Math.min(mapscalez-1,Math.max(0,Math.floor(z)));

//Project the 2D coord into a 1D coord for map sampling,--
//and then return the map value scaled into world coordinates
return(mapcol[(x+z*mapscalex)]*tilescaley);
}


• What is the value range for mapcol? Is it also 0 to 255? Jul 9 '20 at 9:49

From a short review;

• the tilescale is 16 which is a great value to multiply or divide with, so

x = x/tilescale;
z = z/tilescale;


can become

x = x >> 4; //Divide by 16 (tilescale)
z = z >> 4; //Divide by 16 (tilescale)


this does mean that changing the tilescale can become a performance drag (like in real games)

• So are 256 and 4, so

return(mapcol[(x+z*mapscalex)]*tilescaley);


could be

return(mapcol[(x+z<<8)]<<2); //Nice comment here

• ~~ is faster than Math.floor() but for negative values it does return ~~-6.3 -> 6

• Don't count on Math to be fast, I dont think I've ever seen Math be faster in anything, even an if statement is faster than Math.max(0,Math.floor(x))

• When you know that x or z are either negative or greater than 255, why not just exit with a fixed value?

• Check out 8 bit arrays, they might reduce the need for clamping in your code

• Thanks so much! I face palmed on the bit shifts. Should have been obvious, though I hadn't known it was a faster op in Javascript. And I hadn't ever heard of the '~~'. That'll be useful just about everywhere! Cheers!
– KECG
Jul 10 '20 at 2:24