3
\$\begingroup\$

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);
}

Many little pixel guys, all of whom must call the above function :)

\$\endgroup\$
1
  • \$\begingroup\$ What is the value range for mapcol? Is it also 0 to 255? \$\endgroup\$
    – konijn
    Jul 9 '20 at 9:49
3
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ 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! \$\endgroup\$
    – KECG
    Jul 10 '20 at 2:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.