布雷森汉姆光栅直线算法,用于计算光栅图中两点间的直线经过的点,因为其简单高效,被广泛使用。
在网格图中,怪物从A点移动到B点,如果允许怪物走对角线,那么最简单的移动方式就是从x,y方向上同时向目标点靠近,
直到其中方向距离为0,接下来从另一个方向上向目标点移动,那么表现上就是先走对角然后走直线。BTW,A*
算法中的启发函数h,
在允许对角线移动的网格图中就可以用这种方法计算,称为octile算法,相比曼哈顿距离更精确,比欧氏距离更简单。
1 | h = max(dx, dy) + (sqrt2 - 1) * min(dx, dy) |
本文简单介绍了该算法的推导过程,并用Erlang实现了该算法。
推导过程
给定起始点(X0,Y0), (X1, Y1),先考虑特殊情况,斜率范围从0到1,X0<X1, Y0<Y1。
那么x每前进1步,y前进距离为m,其中m=dy/dx, 我们用e记录y前进的累积值,x每前进1步,e=e+m。
当e>0.5时,应当使y也前进1步,并将1从e中扣去:e=e-1。
概括起来就是一个判断条件,两种更新策略:
1 | // e = 0; |
优化
为了去掉除法和浮点计算,我们令D = 2*dx*e - dx
, 带入上面的三个公式,上面的判断条件和更新策略变成这样:
1 | // D = -Dx; |
初始e=0, 所以D=-dx,然后每次D增加2dy,当D>0时,减去2dx。
实现
实现的时候需要把特殊情况一般化。下面的代码给出了一个一般化的计算过程。首先根据轴的长短选择主轴,
主轴就是每次前进一个单位的轴。然后根据起点和终点的大小决定前进的方向,终点大于起点,则+1,否则-1.
1 | plot({X0, Y0}, {X1, Y1}) -> |