Hex support

Hexagonal cell layout is supported in several parts of the toolkit, most notably in Console display, Cellular generator, FOV and Pathfinding. This page explains how to uses hexes with rot.js.

While hexagonal cells provide several advantages over the traditional square/rectangular topologies, there is one big complication associated with their usage: there is no canonical way to index individual hexes. A hexagonal indexing comparison document is available for reference; rot.js is using the third variant, called double width.

Displaying hexes

There is a very trivial trick to display a rudimentary hexagonal layout: skip even/odd cells in odd/even rows. No special adjustments are necessary. The result will look good as long as the font aspect ratio is close to 1:√3 – which is the case for most monospaced fonts.

var display = new ROT.Display({width:8, height:5}); SHOW(display.getContainer()); for (var y = 0; y < 5; y++) { for (var x = y%2; x < 8; x += 2) { display.draw(x, y, "•"); } }

For more advanced hexagonal stuff, switch the display to "hex" layout. This has the following advantages:

var display = new ROT.Display({width:8, height:5, layout:"hex"}); SHOW(display.getContainer()); for (var y = 0; y < 5; y++) { for (var x = y%2; x < 8; x += 2) { var bg = ["#333", "#666", "#999", "#ccc", "#fff"].random(); display.draw(x, y, "•", "#000", bg); } }

Cellular dungeon generator

Pass the topology:6 option to the ROT.Map.Cellular constructor to operate in hexagonal mode.

var w = 100, h = 50; var display = new ROT.Display({width:w, height:h, fontSize:10, layout:"hex"}); SHOW(display.getContainer()); /* hexagonal map and rules */ var map = new ROT.Map.Cellular(w, h, { topology: 6, born: [4, 5, 6], survive: [3, 4, 5, 6] }); /* initialize with irregularly random values */ for (var i=0; i<w; i++) { for (var j=0; j<h; j++) { var dx = i/w - 0.5; var dy = j/h - 0.5; var dist = Math.pow(dx*dx+dy*dy, 0.3); if (ROT.RNG.getUniform() < dist) { map.set(i, j, 1); } } } /* generate four iterations, show the last one */ for (var i=4; i>=0; i--) { map.create(i ? null : display.DEBUG); }

Pathfinding

All pathfinding algorithms accept the topology:6 option as well.

var w = 150, h = 80; ROT.RNG.setSeed(12345); var display = new ROT.Display({width:w, height:h, fontSize:6, layout:"hex"}); SHOW(display.getContainer()); /* generate map and store its data */ var data = {}; var map = new ROT.Map.Cellular(w, h, { topology: 6, born: [4, 5, 6], survive: [3, 4, 5, 6] }); map.randomize(0.48); map.create(); /* two iterations */ map.create(function(x, y, value) { data[x+","+y] = value; display.DEBUG(x, y, value); }); /* input callback informs about map structure */ var passableCallback = function(x, y) { return (data[x+","+y] === 0); } /* prepare path to given coords */ var dijkstra = new ROT.Path.Dijkstra(120, 64, passableCallback, {topology:6}); /* compute from given coords */ dijkstra.compute(30, 16, function(x, y) { display.draw(x, y, "", "", "#800"); }); /* highlight */ display.draw(30, 16, "", "", "#3f3"); display.draw(120, 64, "", "", "#f33");

Field of View

Precise Shadowcasting works in hexagonal topology as well.

ROT.RNG.setSeed(12345); ROT.DEFAULT_WIDTH = 44; ROT.DEFAULT_HEIGHT = 28; var display = new ROT.Display({fontSize:12, layout:"hex"}); SHOW(display.getContainer()); /* generate map and store its data */ var data = {}; var map = new ROT.Map.Cellular(null, null, { topology: 6, born: [4, 5, 6], survive: [3, 4, 5, 6] }); map.randomize(0.4); map.create(function(x, y, value) { data[x+","+y] = value; display.DEBUG(x, y, value); }); /* input callback */ var lightPasses = function(x, y) { var key = x+","+y; if (key in data) { return (data[key] == 0); } return false; } var fov = new ROT.FOV.PreciseShadowcasting(lightPasses, {topology:6}); /* output callback */ fov.compute(20, 14, 6, function(x, y, r, vis) { var ch = (r ? "" : "@"); var color = (data[x+","+y] ? "#aa0": "#660"); display.draw(x, y, ch, "#fff", color); });