笔记2

如果美术给的地图路径和格子路径不一致,优化方案:
#include <stdlib.h>
// #include <stdio.h>
//#include <memory.h>
//#include "conio.h"
#include <string.h>

#include "FindPath.h"

static unsigned int MapWidth;					// 地图宽
static unsigned int MapHeight;					// 地图高

// 8个方向邻居跟自己位置偏移,从12点方向开始,顺时针
const int DIR_XY[8][2] = {{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1},{-1, 1}, {-1, 0}, {-1, -1}};
const int DIR_G[8] = {10, 14, 10, 14, 10, 14, 10, 14};

// 在地图更新时,建立新的Astar寻路用的地图寻路格子信息
// BlockValue 就是地图格子上定义好的阻挡信息,'*' 表示可以通行,其他不能通行
struct _AstarNode *NewAstarMap(int W, int H, unsigned char *BlockValue)
{
	struct _AstarNode *AstarMap = (struct _AstarNode *)malloc(W * H * sizeof(struct _AstarNode));
	if (AstarMap == NULL)
		return NULL;

	memset(AstarMap, 0, W * H * sizeof(struct _AstarNode));
	
	MapWidth = W;
	MapHeight = H;

	unsigned char *P = BlockValue;
	struct _AstarNode *Node = AstarMap;		
	for(int y=0; y<H; y++)
	{
		unsigned char *P = BlockValue + y * W; 
		for(int x=0; x<W; x++)
		{
			Node->X = x;
			Node->Y = y;
			Node->Value = ( *P != 0 ) ? 0 : 1;	// 不为0 可通过
			
			P++;
			Node++;
		}
	}
	
	return AstarMap;
}

// 每开始一次新的寻路,初始化Astar地图信息
void InitAstarMap(struct _AstarNode *AstarMap)
{
	for(int y=0; y<MapHeight; y++)
	{
		for(int x=0; x<MapWidth; x++)
		{
			AstarMap->F = 0;
			AstarMap->G = 0;
			AstarMap->Father = NULL;
			AstarMap->Status = 0;
			AstarMap->Next = NULL;
            		AstarMap->dir = 0;
			AstarMap ++;
		}
	}	
}

// 在邻居中中找小等于自己的最大F值所在的节点, 它还要必须在OpenList中
// 后面要用它来加快在OpenList中的定位
struct _AstarNode *FindNearNode(struct _AstarNode *AstarNode)
{
	struct _AstarNode *Node;
	struct _AstarNode *Max_Node = NULL;
	unsigned int Max_F = 0;
	unsigned int _X;
	unsigned int _Y;

	for(int i=0; i<8; i++)
	{
		// 计算邻居的XY
		_X = AstarNode->X + DIR_XY[i][0];
		_Y = AstarNode->Y + DIR_XY[i][1];
			
		// 检查是否已经超过地图界限
		if (_X < 0 || _X >= MapWidth || _Y < 0 || _Y >= MapHeight)
			continue;

		// 通过自己和邻居的相对位于来计算它的地址
		Node = AstarNode + DIR_XY[i][1] * MapWidth + DIR_XY[i][0];
		
		// 不在OpenList中,下一个
		if (Node->Status != 1)
			continue;

		// 大于自己的F,下一个
		if (Node->F > AstarNode->F)
			continue;

		if (Node->F > Max_F)
		{
			Max_F = Node->F;
			Max_Node = Node;
		}	
	}

	return Max_Node;
}

// 插入一个新的OpenList节点
// 暂时采用简单优化的遍历方法
void InsertNode(struct _AstarNode *AstarNode, struct _AstarNode *OpenList)
{
	struct _AstarNode *Node = OpenList->Next;
	struct _AstarNode *PreNode = OpenList;

	// 如果邻居中F值比自己小,而且在OpenList中,以它为起点去扫描
	// 为了最大化效率,这个邻居的F值还是最接近自己的F
	struct _AstarNode *NearNode = FindNearNode(AstarNode);
	if (NearNode != NULL)
		Node = NearNode;

	AstarNode->Status = 1;		// Opened

	while(Node != NULL)
	{
		if (Node->F > AstarNode->F)
		{
			PreNode->Next = AstarNode;
			AstarNode->Next = Node;
			return;
		}
	
		PreNode = Node;
		Node = Node->Next;	
	}
	
	// 到了这里,表示AstarNode应该插到OpenList的最后
	PreNode->Next = AstarNode;
	AstarNode->Next = NULL;	
}

// 摘取出OpenList的第一个节点
struct _AstarNode *Pop(struct _AstarNode *OpenList)
{
	struct _AstarNode *P = OpenList->Next;
	OpenList->Next = P->Next;
	
	P->Next = NULL;
	P->Status = 2;		// Closed

	return P;
}


// 寻路
// 返回的是路径的开始点,然后Next,Next一路找下去
struct _AstarNode *FindPath(int SrcX, int SrcY, int DstX, int DstY, struct _AstarNode *AstarMap)
{
	if ( SrcX == DstX && SrcY == DstY )
		return NULL;

	bool IsFounded = false;
	
	struct _AstarNode *StartNode = AstarMap + SrcY * MapWidth + SrcX;	
	struct _AstarNode *StopNode = AstarMap + DstY * MapWidth + DstX;
	struct _AstarNode *CurNode, *ChildNode;
	int G, F, H;

	H = abs(SrcX - DstX)*10 + abs(SrcY - DstY)*10;

	struct _AstarNode OpenList;
	OpenList.Next = NULL;

	// 如果源本身就是一个阻隔点,直接返回StopNode作为路径的开始点 // 如果目标本身就是一个阻隔点, 直接返回失败
	if (StartNode->Value > 0 || StopNode->Value > 0 )
		return NULL;

	// 源和目标一样,直接返回StartNode作为路径的开始点
	if (StartNode->X == StopNode->X && StartNode->Y == StopNode->Y)
	{
		StartNode->Next = NULL;
		return(StartNode);
	}
	
	InsertNode(StartNode, &OpenList);
	
	unsigned int DD;
	unsigned int _X;
	unsigned int _Y;

	while( !IsFounded )
	{
		// 找F值最小的节点作为当前节点
		CurNode = Pop(&OpenList);

		if (CurNode == NULL)		// 如果为NULL,表示 OpenList 已经为空,寻路结束
			break;
		
		// 检查当前节点八个方向的邻居
		// 路径平滑处理,引入DirCount,是为了让保证原方向优先,降低W型路径的出现机会
		static unsigned int DirCount = CurNode->dir;
		for(int i=0; i<8; i++, DirCount++)
		{
			// 计算邻居的XY
			DD = DirCount%8;
			_X = CurNode->X + DIR_XY[DD][0];
			_Y = CurNode->Y + DIR_XY[DD][1];
			
			// 检查是否已经超过地图界限
			if (_X < 0 || _X >= MapWidth || _Y < 0 || _Y >= MapHeight)
				continue;

			ChildNode = AstarMap + _Y * MapWidth + _X;
			
			// 邻居是不可通行格子,下一个。(暂时只支持0,1模式)
			if (ChildNode->Value > 0)
				continue;
			
			// 邻居为 Closed,下一个
			if (ChildNode->Status == 2)
				continue;
			
			// 计算邻居的G、H、F值
            if (DD == CurNode->dir)
            {
                G = CurNode->G + (DIR_G[DD] / 2);
            } else
            {
                G = CurNode->G + DIR_G[DD];
            }
			F = H + G;
			
			if (ChildNode->Status != 1)
			{
				// 不在OpenList,插入
				ChildNode->Father = CurNode;
				ChildNode->G = G;
				ChildNode->F = F;
                ChildNode->dir = DD;

				InsertNode(ChildNode, &OpenList);
				
				// 检查是否为 目标点,是就表示找到,结束寻路
				if (ChildNode->X == StopNode->X && ChildNode->Y == StopNode->Y)
				{
					IsFounded = true;
					break;
				}
			}
			else
			{
				// 邻居在 OpenList 中,
				// 如果邻居现在的G值比在OpenList的G值小,更新它
				// 下面这段代码不能提前,否则会导致G提前被修改
				if (ChildNode->G > G)
				{
					ChildNode->G = G;
					ChildNode->F = F;
					ChildNode->Father = CurNode;
                    ChildNode->dir = DD;
				}
			}

		}	// end For
		 
	}	// end While

	// 路径存在,从 目标点 回溯到 开始点,产生正向路径
	// 从开始点开始,借用Next来保存路径
	if (IsFounded == true)
	{
		struct _AstarNode *P = StopNode;
		struct _AstarNode *Father;
		
		P->Next = NULL;				// 设置路径最后标志

		while(P != NULL)
		{
			Father = P->Father;

			if (Father == NULL)		// 异常检查,保持不会出现Core
				return NULL;

			Father->Next = P;
			if (Father->X == StartNode->X && Father->Y == StartNode->Y)
				break;
			else
				P = Father;
		}

		return(Father);
	}
	else
	{
		return NULL;
	}	
}

//const unsigned char MapBlocks[20][16] = {
//	{"**************"},
//	{"**************"},
//	{"**************"},
//	{"           ***"},
//	{"           ***"},
//	{"           ***"},
//	{"          *** "},
//	{"         ***  "},
//	{"        ***   "},
//	{"       ***    "},
//	{"      ***     "},
//	{"     ***      "},
//	{"    ***       "},
//	{"   *********  "},
//	{"  **********  "},
//	{" ***********  "},
//	{"************  "},
//	{"************  "},
//	{"**************"},
//	{"              "}
//};      
//
//
//
//int main(void)
//{
//	struct _AstarNode *AStarMap = NewAstarMap(16, 20, (unsigned char *)MapBlocks);
//	if (AStarMap == NULL)
//	{
//		printf("Map Init Error\n");
//		return(0);
//	}
//
//	printf("MapBlocks: [*] OK \n");
//	for(int i=0; i<20; i++)
//	{
//		printf("%02d:|%s|\n", i, (unsigned char *)MapBlocks+i*16);
//	}
//	
//	InitAstarMap(AStarMap);
//
//	struct _AstarNode *Path = FindPath(0, 1, 1, 16, AStarMap);
//	if (Path == NULL)
//	{
//		printf("Path Not Found\n");
//		return(0);
//	}
//	
//
//	printf("RoutePoint: ");
//	while(Path->Next != NULL)
//	{
//		printf("[%d,%d]->", Path->X, Path->Y);
//
//		Path = Path->Next;
//	}
//
//	printf("[%d,%d]  End! ", Path->X, Path->Y);
//
//	getch();
//
//	delete(AStarMap);
//}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值