1

I am working on a text based (console) WW2 strategy game, set on a 2d square grid map. I want a method to calculate line of sight from one tile on the map to another. I've used this Java example to base my code off, this is what I've written:

public function plotLine($x0, $y0, $x1, $y1, $size)
{   
    $arr = $this->getEmptyMap($size);
    $xDist = abs($x1 - $x0);
    $yDist = -abs($y1 - $y0);
    if($x0 < $x1) {
        $xStep = 1;
    } else {
        $xStep = -1;
    }

    if($y0 < $y1) {
        $yStep = 1;
    } else {
        $yStep = -1;
    }

    $plotError = $xDist + $yDist;

    $arr[$x0][$y0] = 1;

    while($x0 != $x1 || $y0 != $y1) {
        // if(2 * $plotError > $yDist) {
        //  // Horizontal step
        //  $plotError += $yDist;
        //  $x0 += $xStep;
        // }

        // if(2 * $plotError < $xDist) {
        //  // Vertical step
        //  $plotError += $xDist;
        //  $y0 += $yStep;
        // }

        if(2 * $plotError - $yDist > $xDist - 2 * $plotError) {
            // Horizontal step
            $plotError += $yDist;
            $x0 += $xStep;
        } else {
            // Vertical step
            $plotError += $xDist;
            $y0 += $yStep;
        }           


        $arr[$x0][$y0] = 1;
    }

    $this->line = $arr;
}

Note: getEmptyMap just fills a multidimensional array with 0's.

Testresult using (0, 0, 4, 4, 4) as input:

1100
0110
0011
0001

I've tried to ways of mapping the line: one is the normal implementation that Franz D. used (currently commented out in my example above), the other is the modified implementation that Franz D. showed. Neither is giving me the result I'm looking for; a kind of "anti-aliasing". When a solder would look from 0,0 at 2,2 and there would be buildings at 1,2 and 2,1, whatever is at 2,2 should be blocked from sight. The commented out implementation would completely ignore the buildings, the modification does "hit" 2,1 but not 1,2. How would I adjust my code to "hit" both underneath the line and above the line?

Community
  • 1
  • 1
Somentus
  • 95
  • 2
  • 11
  • if you think that algorithm is the best fit for your task, why not try it first, if you're not yet used using PHP, learn the tool first, then port the algorithm in PHP flavor – Kevin Nov 20 '16 at 23:50
  • I gave it a try and worked out an implementation, but I still come across a problem (see edit in post) – Somentus Nov 21 '16 at 01:06

1 Answers1

1

The 'problem' you are facing happens because of the special edge case when looking at an exact diagonal. There are 'only' two (simple) possibilities of handling this:

1) A diagonal increments a horizontal and vertical tile at the same time. In your game, this would mean that units would be able to look at the diagonals, even if the cardinal directions would be blocked.

2) Choose between giving precedence to the horizontal tiles or the vertical tiles and only ever incrementing one of the two. This is the algorithm of Franz D. that you ended up writing and placing in your post. Here, the if-statement is true for diagonals, which means that the result will be:

1100
0110
0011
0001

If you want the verticals to have precedence, you can alter it to:

...
        if(2 * $plotError - $yDist < $xDist - 2 * $plotError) {
            // Vertical step
            $plotError += $xDist;
            $y0 += $yStep; 
        } else {
          // Horizontal step
            $plotError += $yDist;
            $x0 += $xStep;
        }  

...

Note that both the bodies of the if/else are swapped, and the > was changed into < in the condition.

Now, the result will be:

1000
1100
0110
0011

If you want a unit to only be able to look to the diagonals if there is nothing blocking éither of the adjacent cardinals, the simplest solution would be to use both of above variants of the algorithm, and combine their results into one single array of tiles.

One final note: if you are only interested in the coordinates and not in their values (as seems to be the case for the use case you describe), it might be more (memory)efficient to use a simple array of extracted (x, y) coordinates instead of a two-dimensional array of the complete map which you afterwards loop over to extract all (x, y) coordinates where the result is a 1.

Good luck with the game!

Qqwy
  • 5,214
  • 5
  • 42
  • 83