Spaces:
Running
Running
<h2>Hex support</h2> | |
<p>Hexagonal cell layout is supported in several parts of the toolkit, most notably in <a href="#display">Console display</a>, <a href="#map/cellular">Cellular generator</a>, <a href="#fov">FOV</a> and <a href="#path">Pathfinding</a>. This page explains how to uses hexes with rot.js.</p> | |
<p>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 <a href="#hex/indexing">hexagonal indexing comparison</a> document is available for reference; rot.js is using the third variant, called <em>double width</em>. | |
<h3>Displaying hexes</h3> | |
<p>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 <code>1:√3</code> – which is the case for most monospaced fonts.</p> | |
<div class="example"> | |
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, "•"); | |
} | |
} | |
</div> | |
<p>For more advanced hexagonal stuff, switch the display to "hex" layout. This has the following advantages:</p> | |
<ul> | |
<li>Precisely computed positioning</li> | |
<li>Filled background hexes</li> | |
</ul> | |
<div class="example"> | |
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); | |
} | |
} | |
</div> | |
<h2>Cellular dungeon generator</h2> | |
<p>Pass the <code>topology:6</code> option to the <code>ROT.Map.Cellular</code> constructor to operate in hexagonal mode.</p> | |
<div class="example"> | |
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); | |
} | |
</div> | |
<h2>Pathfinding</h2> | |
<p>All pathfinding algorithms accept the <code>topology:6</code> option as well.</p> | |
<div class="example"> | |
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"); | |
</div> | |
<h3>Field of View</h3> | |
<p>Precise Shadowcasting works in hexagonal topology as well.</p> | |
<div class="example"> | |
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); | |
}); | |
</div> | |