【问题标题】:Bresenham's Line Algorithm in PHPPHP 中的 Bresenham 线算法
【发布时间】:2016-11-20 23:42:01
【问题描述】:

我正在开发基于文本(控制台)的二战战略游戏,设置在 2d 方形网格地图上。我想要一种方法来计算从地图上的一个图块到另一个图块的视线。我使用this Java 示例作为我的代码的基础,这就是我写的:

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

注意:getEmptyMap 只是用 0 填充多维数组。

使用 (0, 0, 4, 4, 4) 作为输入的测试结果:

1100
0110
0011
0001

我尝试了映射线的方法:一种是 Franz D. 使用的正常实现(目前在我上面的示例中已注释掉),另一种是 Franz D. 展示的修改后的实现。也没有给我我正在寻找的结果;一种“抗锯齿”。当焊料从 0,0 看 2,2 并且在 1,2 和 2,1 处有建筑物时,应将 2,2 处的任何东西挡在视线之外。注释掉的实施将完全忽略建筑物,修改确实“击中” 2,1 但不是 1,2。我将如何调整我的代码以“命中”在线下方和在线上方?

【问题讨论】:

  • 如果您认为该算法最适合您的任务,为什么不先尝试一下,如果您还没有使用 PHP,请先学习该工具,然后将算法移植到 PHP 风格
  • 我试了一下并制定了一个实现,但我仍然遇到问题(请参阅帖子中的编辑)

标签: php algorithm oop multidimensional-array bresenham


【解决方案1】:

您面临的“问题”是由于查看精确对角线时的特殊边缘情况而发生的。处理这个问题“只有”两种(简单)的可能性:

1) 对角线同时增加水平和垂直平铺。在您的游戏中,这意味着单位将能够查看对角线,即使主要方向会被阻挡。

2) 在优先考虑水平平铺或垂直平铺之间进行选择,并且只增加两者之一。这是您最终编写并放置在帖子中的 Franz D. 的算法。这里,if-语句对于对角线是正确的,这意味着结果将是:

1100
0110
0011
0001

如果您希望垂直行业具有优先权,您可以将其更改为:

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

...

请注意,if/else 的两个主体都交换了,条件中的&gt; 更改为&lt;

现在,结果将是:

1000
1100
0110
0011

如果您希望一个单元只能在没有任何东西阻挡相邻基数的情况下查看对角线,最简单的解决方案是使用算法的上述两种变体,并将它们的结果合并为一个瓷砖数组。

最后一点:如果您只对坐标而不是它们的值感兴趣(您描述的用例似乎就是这种情况),那么使用提取的简单数组可能会更(内存)效率更高(x, y) 坐标而不是完整地图的二维数组,之后您循环提取所有(x, y) 坐标,结果为1

祝游戏好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    相关资源
    最近更新 更多