2
\$\begingroup\$

I got a turret that points at the corner of hexagon (point A). It can shoot in cover arc that's shown here: enter image description here

I need to check if my target lies within this cover arc. From this tutorial: Hexagonal Grids I know how to get a hexgrid coordinate of my target by cliking on it.

How can I get coordinates of all the hexes in cover arc (not only red hexes but all that lie within CA)?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It's a Pascal's Triangle. \$\endgroup\$ Jan 13, 2018 at 2:17

1 Answer 1

6
\$\begingroup\$

I prefer to do hex-cell coordinate math in what Amit calls cubical coordinates on your linked page. For the rest of this answer, (X, Y, Z) will refer to cubical coordinates.

Basically, for any of the 6 sectors you're interested in, one of the positive or negative X, Y, or Z axes will correspond to the radial distance. For example, in Figure 1, as X increases in the northeast sector, the distance gets further away.

enter image description here

The other two coordinates are chosen such that they are less in magnitude than the radius (so you don't go past the left and right borders of the sector). Again, referring to Figure 1, When X is 2, (Y, Z) goes (0 -2), (-1, -1), (-2, 0). Due to the rules of the cubical coordinates, Y and Z must add up to -2, and they cannot be (-3, 1) for example because they cannot be larger than X in magnitude.

Putting this together, given a particular sector, you choose one of X, -X, Y, -Y, Z, -Z as the radius axis and then iterate along two other axes such that the two axes plus the radius always equals 0 (to satisfy the cubical coordinate constraint) and whose absolute values are less than the radius. In pseudocode:

 for(var radius = 0; radius <= 4; radius++) {
     for(var a = 0; a >= -radius; a--) { 
         var b = - radius - a;
         /*
        At this point we have 3 coordinates that satisfy the cubical condition: (radius, a, b) and radius + a + b == 0. 
        Depending on the sector, we choose all hexes with coordinates (x, y, z) such that:
        Sector 1: (x, y, z) = (r, a, b) :: X is the radius
        Sector 2: (x, y, z) = (-a, -b, -r) :: -Z is the radius
        Sector 3: (x, y, z) = (b, r, a) :: Y is the radius
        Sector 4: (x, y, z) = (-r, -a, -b) :: -X is the radius
        Sector 5: (x, y, z) = (a, b, r) :: Z is the radius
        Sector 6: (x, y, z) = (-b, -r, -a) :: -Y is the radius
          */
     }
 }

To check figure out which sector any particular hex cell with coordinate (X, Y, Z) belongs to, you can check that it obeys the following rules.

  • Sector 1: Y <= 0 && Z <= 0
  • Sector 2: X >= 0 && Y >= 0
  • Sector 3: Z <= 0 && X <= 0
  • Sector 4: Y >= 0 && Z >= 0
  • Sector 5: X <= 0 && Y <= 0
  • Sector 6: Z >= 0 && X >= 0

Interactive Demo:

var w = document.body.clientWidth, h = 400, r = 5;
 var $new = x => document.createElementNS("http://www.w3.org/2000/svg", x);
 var $attrs = (e, attrs) => { for(var k in attrs) e.setAttribute(k, attrs[k]); return e; };
 $attrs(demo, {width: w, height: h, viewbox: `0 0 ${w} ${h}`});

 // on mouse over, we highlight the current sector
 function onMouseOver(e) {
     var coords = this.id.split('_').slice(1);
     var sector =
	 coords[1] <= 0 && coords[2] <= 0 ? 0 :
	 coords[0] >= 0 && coords[1] >= 0 ? 1 :
	 coords[2] <= 0 && coords[0] <= 0 ? 2 :
	 coords[1] >= 0 && coords[2] >= 0 ? 3 :
	 coords[0] <= 0 && coords[1] <= 0 ? 4 :
	 5;
     highlightSector(sector, 4);
 }

 // -------------------- Initialize All tiles --------------------
 function createTile(x, y, z) {
     var u = x * 40 - y * 40, v = z * 60, g = $attrs($new('g'), {
	 id: `a_${x}_${y}_${z}`,
	 transform: `translate(${w/2 + u},${h/2 + v})`,
     });
     g.addEventListener('mouseover', onMouseOver);
     var t = $new('text');
     t.innerHTML = [x, y, z];
     g.appendChild(t);
     g.appendChild($attrs($new('polygon'), { points: "0,-40 40,-20 40,20 0,40 -40,20 -40,-20" }));
     demo.appendChild(g);
 }
 for(var z = -r; z <= r; z++)
     for(var x = -r; x <= r; x++) 
	 if (!(z + x > r || z + x < -r)) createTile(x, -z - x, z);

 
 function highlight(x, y, z, h) { document.getElementById(`a_${x}_${y}_${z}`).setAttribute('class', h); }

 function highlightSector(sector, maxRadius) {
     var e2 = Array.prototype.slice.call(document.getElementsByClassName('h'));
     for(var i=0; i<e2.length; i++) e2[i].setAttribute('class', '');

     for(var radius = 0; radius <= maxRadius; radius++) {
	 for(var a = 0; a >= -radius; a--) { 
	     var b = - radius - a;
	     /*
		At this point we have 3 coordinates: (radius, a, b). 
		Depending on the sector, we choose all hexes with coordinates (x, y, z) such that:
		Sector 1: (x, y, z) = (r, a, b)
		Sector 2: (x, y, z) = (-a, -b, -r)
		Sector 3: (x, y, z) = (b, r, a)
		Sector 4: (x, y, z) = (-r, -a, -b)
		Sector 5: (x, y, z) = (a, b, r)
		Sector 6: (x, y, z) = (-b, -r, -a)
	      */
	     if (sector == 0) highlight(radius, a, b, 'h');
	     if (sector == 1) highlight(-a, -b, -radius, 'h');
	     if (sector == 2) highlight(b, radius, a, 'h');
	     if (sector == 3) highlight(-radius, -a, -b, 'h');	 
	     if (sector == 4) highlight(a, b, radius, 'h');
	     if (sector == 5) highlight(-b, -radius, -a, 'h');
	 }
     }
 }
<!doctype html>
<style>
 g { stroke:#368; fill: #99bbcc66; text-anchor:middle;}
 g:hover { stroke:red; stroke-width:2.5; }
 .h { stroke-width:3; stroke:green; }
</style>

<svg id="demo"> </svg>

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .