游戏中DDA算法和Bresenham算法的应用

在角色扮演或即时战略游戏中,经常会将角色以最佳的方式走到指定地点。游戏场景的地面情况复杂,而且场面大,若采用盲目式搜索,例如盲目穷举法,则几乎要遍历整个场景,效率非常低,造成角色反应速度过慢,实践证明是一种不适合网络游戏寻路方法。而启发式搜索算法在障碍较少的情况下也显得效率过低。

DDA算法和Bresenham算法是游戏寻路中绘制直线的两种常用算法。

在列举这两算法之前,我先定义坐标的结构体代码:

struct PixelNode
{
	uint16_t x;
	uint16_t y;
};

数值微分画线算法(DDA)法是直线生成算法中最简单的一种,它是一种单步直线生成算法。它的算法是这样的:首先根据直线的斜率确定是以X方向步进还是以Y方向步进,然后沿着步进方向每步进一个点(象素),就沿另一个坐标变量k,k是直线的斜率,因为是对点阵设备输出的,所以需要对每次计算出来的一对坐标进行圆整。

具体算法的实现,除了判断是按照X方向还是按照Y方向步进之外,还要考虑直线的方向,也就是起点和终点的关系。

DDA算法的描述以及原理:

设(x1,y1)和(x2,y2)分别为所求直线的起点和终点坐标,由直线的微分方程得

可通过计算由x方向的增量△x引起y的改变来生成直线:

也可通过计算由y方向的增量△y引起x的改变来生成直线:

选定x2-x1和y2-y1中较大者作为步进方向(假设x2-x1较大),取该方向上的增量为一个象素单位(△x=1)。

然后利用式(2-1)计算另一个方向的增量(△y=△x·m=m)。通过递推公式(2-2)至(2-5),把每次计算出的(xi+1,yi+1)

经取整后送到显示器输出,则得到扫描转换后的直线。   之所以取x2-x1和y2-y1中较大者作为步进方向,是考虑沿

着线段分布的象素应均匀,这在下图中可看出。

另外,算法实现中还应注意直线的生成方向,以决定Δx及Δy是取正值还是负值。

所以他的实现步骤是这样描述的:

1、已知直线的两端点坐标:(x1,y1),(x2,y2)

2、已知画线的颜色:color

3、计算两个方向的变化量:dx=x2-x1                dy=y2-y1

4、求出两个方向最大变化量的绝对值:

steps=max(|dx|,|dy|)

5、计算两个方向的增量(考虑了生成方向):                xin=dx/steps                yin=dy/steps

6、设置初始象素坐标:x=x1,y=y1

7、用循环实现直线的绘制:

for(i=1;i<=steps;i++)
{
    	putpixel(x,y,color);/*在(x,y)处,以color色画点*/
	x=x+xin;
	y=y+yin;
}

下面给一段code来说明一下这个算法:

bool DDA::CalcLineNodes(int x1, int y1, int x2, int y2,vector<PixelNode>& pointList) {
	float increx,increy,x,y;
	int steps,i;
	if(x1 == x2 && y1 == y2){
		return false;
	}
	pointList.clear();
	if(abs(x2 - x1) > abs(y2 - y1)) {
		steps= abs(x2 - x1);
	}
	else {
		steps = abs(y2-y1);
	}
	increx = (float)(x2 - x1)/steps;
	increy = (float)(y2 - y1)/steps;
	x = x1;
	y = y1;
	for(i = 1;i <= steps;i ++)  {
		//putpixel(x, y, color); //在(x,y)处,以color色画点
		PixelNode p(x,y);
		pointList.push_back(p);
		x+=increx;
		y+=increy;
   }
   return true;
}

但是实际上数值微分法(DDA法)产生的直线比较精确,而且逻辑简单,易于用硬件实现,但是步进量x,y和k必须用浮点数表示,每一步都要对x或y进行四舍五入后取整,不利于光栅化或点阵输出。生成直线的时间较长。

bresenham算法的特点以及原理:

由直线的斜率确定选择在x方向或y方向上每次递增(减)1个单位,另一变量的递增(减)量为0或1,它取决于实际直线与最近光栅网格点的距离,这个距离的最大误差为0.5。

假定直线斜率k在0~1之间。此时,只需考虑x方向每次递增1个单位,决定y方向每次递增0或1。

设直线当前点为(xi,y)

直线当前光栅点为(xi,yi)

则下一个直线的点应为(xi+1,y+k)   下一个直线的光栅点为右光栅点(xi+1,yi)(y方向递增量0)或为右上光栅点(xi+1,yi+1)(y方向递增量1)

记直线与它垂直方向最近的下光栅点的误差为d,有:d=(y+k)–yi,且

0≤d≤1   当d<0.5:下一个象素应取右光栅点(xi+1,yi)   当d≥0.5:下一个象素应取右上光栅点(xi+1,yi+1)

在这里我给出部分实现的代码:

//返回列表中 包含起始点,不包含目标点
bool Bresenham::CalcLineNodes(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, std::vector<PixelNode>& rNodesVec)
{
	if (x1 == x2 && y1 == y2)
	{
		return false;
	}
	rNodesVec.clear();

    int dx = abs(x2 - x1);//△x
    int dy = abs(y2 - y1);//△y
    int p = (2 * dy) - dx ; //P = 2△y - △x

    int PointX = x1;//起始坐标X
    int PointY = y1;//起始坐标Y

    int StepX = 0;
	int StepY = 0;

	if (y1 < y2)
	{
		StepY = 1;//y递增
	}
	else//y1 > y2
	{
		StepY = -1;//y递减
	}
	if (x1 < x2)
	{
		StepX = 1;//x递增
	}
	else
	{
		StepX = -1;//x递减
	}

    // 达到第一个起始点
	PixelNode pt0;
	pt0.x = PointX;
	pt0.y = PointY;
	rNodesVec.push_back(pt0);

	if (dx > dy)//横向跨度大,以x为步长
	{
		int twoDy = 2 * dy ; // 2 △y
		int twoDyDx = 2 * (dy - dx) ; // 2(△y - △x)
		while (PointX != x2)
		{
			PointX += StepX;

			if (p < 0)
			{
				p += twoDy;
			}
			else
			{
				PointY += StepY;
				p += twoDyDx;
			}

			PixelNode pt;
			pt.x = PointX;
			pt.y = PointY;
			rNodesVec.push_back(pt);

		}

	}
	else//纵向跨度大,以y为步长
	{
		int twoDx = 2 * dx ; // 2 △x
		int twoDxDy = 2 * (dx - dy) ; // 2(△x - △y)

		while (PointY != y2)
		{
			PointY += StepY;

			if (p < 0)
			{
				p += twoDx;
			}
			else
			{
				PointX += StepX;
				p += twoDxDy;
			}

			PixelNode pt;
			pt.x = PointX;
			pt.y = PointY;
			rNodesVec.push_back(pt);

		}
	}

	return true;
}

时间: 2024-10-16 02:55:34

游戏中DDA算法和Bresenham算法的应用的相关文章

使用Apriori算法和FP-growth算法进行关联分析(Python版)

===================================================================== <机器学习实战>系列博客是博主阅读<机器学习实战>这本书的笔记也包含一些其他python实现的机器学习算法 算法实现均采用python github 源码同步:https://github.com/Thinkgamer/Machine-Learning-With-Python ==================================

最短路径Dijkstra算法和Floyd算法整理、

转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径—Dijkstra算法和Floyd算法 Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹

链接挖掘算法之PageRank算法和HITS算法

参考资料:http://blog.csdn.net/hguisu/article/details/7996185 更多数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm 链接分析 在链接分析中有2个经典的算法,1个是PageRank算法,还有1个是HITS算法,说白了,都是做链接分析的.具体是怎么做呢,继续往下看. PageRank算法 要说到PageRank算法的作用,得先从搜索引擎开始讲起,PageRank算法的由来正式与此相关. 搜

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边. 构造最小生成树,要解决以下两个问题: (1).尽可能选取权值小的边,但不能构成回路(也就是环). (2).选取n-1条恰当的边以连接网的n个顶点. Prim算法的思想: 设G = (V,E)是连通带权图,V = {1,2,-,n}.先任选一点(一般选第一个点),首

Prim算法和Kruskal算法的正确性证明

今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证明这两个算法的正确性,更加简洁.优雅并且根本.相比之下,我的证明带着许多草莽气息,于此写成博客,只当是记录自己的思考 ------------------------------------------- 说明: 本文仅提供关于两个算法的正确性的证明,不涉及对算法的过程描述和实现细节 本人算法菜鸟一枚,提供的

最小生成树-Prim算法和Kruskal算法

原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在195

时空权衡之输入增强 ----字符串匹配算法Horspool算法和Boyer-Moore算法

在算法设计的时空权衡设计技术中,对问题的部分或者全部输入做预处理,对获得的额外信息进行存储,以加速后面问题的求解的思想,我们称作输入增强. 其中字符串匹配算法Horspool算法和Boyer-Moore算法就是输入增强的例子. 首先了解一下字符串匹配的概念.我们把在一个较长的n个字符的串中,寻找一个给定的m个字符的串的问题,称为字符串匹配问题.较长的串称为text,而需要寻找的串称为pattern. 字符串匹配问题的蛮力算法很好理解:我们把pattern与text第一个字符对齐,从左往右比较pa

使用Apriori算法和FP-growth算法进行关联分析

系列文章:<机器学习>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章节标题所示,这两章讲了无监督机器学习方法中的关联分析问题.关联分析可以用于回答"哪些商品经常被同时购买?"之类的问题.书中举了一些关联分析的例子: 通过查看哪些商品经常在一起购买,可以帮助商店了解用户的购买行为.这种从数据海洋中抽取的知识可以用于商品定价.市场促销.存活管理等环节. 在美国国会

0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i件物品的重量是w[i],价值是v[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大.其中每种物品只有一件,可以选择放或者不放. 最优子结构性质:对于0-1问题,考虑重量至多W的最值钱的一包东西.如果去掉其中一个物品j,余下的必是除j以外的n-1件物品中,可以带走的重量