能用是能用,但是效率什么的就不好说了,用在客户端还可以,如果是服务器同时算成百上千个NPC和怪物的话肯定不是这种实现方法,还望大家指点......^*^
/*-----------------------------------------------------------------------------------------------------------------
A*寻路算法类
Author: 苗琳
Date: 2009-5-30
Update:
----------------------------------------------------------------------------------------------------------------**/
#pragma once
#include <vector>
#include <list>
class AStar
{
public:
//结点类
class Node
{
public:
//该结点所在地图数组的索引
unsigned int x , z;
//该结点的估价值变量 f (总估价) h(到目标点的估价) g(到开始点的估价)
unsigned int f , h , g;
//该结点的父结点
Node* mParentNode;
//该结点的索引
int nodeIndex;
//是否可走
bool bPass;
};
public:
AStar(void);
~AStar(void);
//加载地图碰撞数据
bool loadMap(unsigned int width , unsigned int height , const std::vector<bool>& mapData);
//搜索路径
bool findPath(unsigned int startX , unsigned int startZ , unsigned int endX , unsigned int endZ);
//清空所有数据,可重新加载地图
void clear();
//获得一个结点的索引
unsigned int getNodeIndex(unsigned int x , unsigned int z);
private:
//获得开启列表中估价最好的结点(排序之后,第一个结点即最佳结点)
Node* getOpenListBestNode();
//搜索所有子结点
void findAllSubNode(Node* pBestNode);
//结点是否存在(注意可以传负数)
bool hasNode(int x , int z);
//处理子结点 传一个父结点,和要处理结点的x,z索引
void handleSubNode(Node* pParentNode , unsigned int x , unsigned int z);
//在开启列表里查找一个结点
Node* findNodeFromOpenList(unsigned int index);
//在关闭列表里查找一个结点
Node* findNodeFromCloseList(unsigned int index);
//重新处理子结点(在关闭列表中发现G值比原来更低的结点时调用)
void rehandleNode(Node* pNode);
//从关闭列表中取出一个结点到开启列表中
void findCloseNodeMoveToOpen(unsigned int index);
//将一个结点插入到开启列表中并重新排序,f值最低的排在最前
void insertNodeToOpenAndOrder(Node* pNode);
private:
std::list<Node*> mOpenList; //开启列表
std::list<Node*> mCloseList; //关闭列表
std::vector<Node> mMapData; //地图结点总列表
unsigned int m_iWidth;
unsigned int m_iHeight;
unsigned int m_iMapSize;
unsigned int m_iStartX , m_iStartZ , m_iEndX , m_iEndZ; //开始点和结束点
bool m_bFound; //是否找到目标点
bool m_bFail; //查找失败,没有可用路径
unsigned int m_iDestIndex; //目标结点的索引
};
/AStar.cpp/
#include "AStar.h"
AStar::AStar(void)
: m_iMapSize(0) , m_bFail(false) , m_bFound(false)
{
}
AStar::~AStar(void)
{
}
//加载地图碰撞数据
bool AStar::loadMap(unsigned int width , unsigned int height , const std::vector<bool>& mapData)
{
clear();
m_iWidth = width;
m_iHeight = height;
m_iMapSize = width * height;
//检测数据有效性
if (mapData.size() != m_iMapSize) return false;
//初始化总结点列表
mMapData.resize(m_iMapSize);
for (size_t j = 0 ; j < m_iHeight ; j++)
{
for (size_t i = 0 ; i < m_iWidth ; i++)
{
unsigned int index = j*m_iWidth+i;
Node* pNode = &mMapData[index];
pNode->nodeIndex = index;
pNode->x = i;
pNode->z = j;
pNode->bPass = mapData[index];
pNode->f = 0;
pNode->g = 0;
pNode->h = 0;
pNode->mParentNode = NULL;
}
}
}
//搜索路径
bool AStar::findPath(unsigned int startX , unsigned int startZ , unsigned int endX , unsigned int endZ)
{
if (!hasNode(startX , startZ)) return false;
if (!hasNode(endX , endZ)) return false;
m_iStartX = startX;
m_iStartZ = startZ;
m_iEndX = endX;
m_iEndZ = endZ;
//计算目标索引
m_iDestIndex = getNodeIndex(endX , endZ);
//估价开始点结点
Node* pStartNode = &mMapData[m_iStartZ * m_iWidth + m_iStartX];
pStartNode->g = 0;
pStartNode->h = (startX - endX) * (startX - endX) + (startZ - endZ) * (startZ - endZ);
pStartNode->f = pStartNode->g + pStartNode->h;
//将开始点的指针加入开启列表
mOpenList.push_back(pStartNode);
while (!m_bFail)
{
Node* pBestNode = getOpenListBestNode();
if (pBestNode->nodeIndex == m_iDestIndex)
{
return true;
}
findAllSubNode(pBestNode);
}
return false;
}
//清空所有数据,可重新加载地图
void AStar::clear()
{
mOpenList.clear();
mCloseList.clear();
mMapData.clear();
m_bFail = false;
m_bFound = false;
}
//获得一个结点的索引
unsigned int AStar::getNodeIndex(unsigned int x , unsigned int z)
{
return z*m_iWidth + x;
}
//获得开启列表中估价最好的结点(排序之后,第一个结点即最佳结点)
AStar::Node* AStar::getOpenListBestNode()
{
if (mOpenList.empty()) return NULL;
//从开启列表中取出首结点,并增加入关闭列表
Node* pNode = mOpenList.front();
mOpenList.pop_front();
mCloseList.push_back(pNode);
return pNode;
}
//结点是否存在(注意可以传负数)
bool AStar::hasNode(int x , int z)
{
if (x >= 0 && x < m_iWidth && z >=0 && z < m_iHeight)
{
return true;
}
else
{
return false;
}
}
//开启列表里查找一个结点
AStar::Node* AStar::findNodeFromOpenList(unsigned int index)
{
Node* pNode = NULL;
std::list<Node*>::iterator itr = mOpenList.begin();
while (itr != mOpenList.end())
{
if ((*itr)->nodeIndex == index)
{
pNode = *itr;
return pNode;
}
++itr;
}
return pNode;
}
//在关闭列表里查找一个结点
AStar::Node* AStar::findNodeFromCloseList(unsigned int index)
{
Node* pNode = NULL;
std::list<Node*>::iterator itr = mCloseList.begin();
while (itr != mCloseList.end())
{
if ((*itr)->nodeIndex == index)
{
pNode = *itr;
return pNode;
}
++itr;
}
return pNode;
}
//重新处理子结点(在关闭列表中发现G值比原来更低的结点时调用)
void AStar::rehandleNode(Node* pNode)
{
//int c,g;
//struct NODE *Child, *Father;
//g=pNode->g; // alias.
//for(c=0;c<8;c++)
//{
// if ((Child=pNode->Child[c])==NULL) // create alias for faster access.
// break;
// if (g+1 < Child->g)
// {
// Child->g=g+1;
// Child->f=Child->g+Child->h;
// Child->Parent=pNode; // reset parent to new path.
// Push(Child); // Now the Child's branch need to be
// } // checked out. Remember the new cost must be propagated down.
//}
//while (Stack->NextStackPtr != NULL)
//{
// Father=Pop();
// for(c=0;c<8;c++)
// {
// if ((Child=Father->Child[c])==NULL) /* we may stop the propagation 2 ways: either */
// break;
// if (Father->g+1 < Child->g) /* there are no children, or that the g value of */
// { /* the child is equal or better than the cost we're propagating */
// Child->g=Father->g+1;
// Child->f=Child->g+Child->h;
// Child->Parent=Father;
// Push(Child);
// }
// }
//}
}
//从关闭列表中取出一个结点到开启列表中
void AStar::findCloseNodeMoveToOpen(unsigned int index)
{
Node* pNode = NULL;
std::list<Node*>::iterator itr = mCloseList.begin();
while (itr != mCloseList.end())
{
if ((*itr)->nodeIndex == index)
{
pNode = *itr;
mCloseList.erase(itr);
mOpenList.push_back(pNode);
break;
}
++itr;
}
}
//将一个结点插入到开启列表中并重新排序,f值最低的排在最前
void AStar::insertNodeToOpenAndOrder(Node* pNode)
{
Node *tmp1,*tmp2;
int f = pNode->f;
//如果开启列表是空的,则直接添加新结点进去
if (mOpenList.empty())
{
mOpenList.push_back(pNode);
return;
}
std::list<Node*>::iterator itr = mOpenList.begin();
while (itr != mOpenList.end())
{
if (f <= (*itr)->f)
{
mOpenList.insert(itr , pNode);
return;
}
++itr;
}
}
//处理子结点
void AStar::handleSubNode(Node* pParentNode , unsigned int x , unsigned int z)
{
int g; //当前结点的G值
int nodeIndex; //当前结点的索引值
int c=0;
Node *pOldNode,*pSubNode;
//计算子节点的 g 值
g = pParentNode->g + 1;
nodeIndex = getNodeIndex(x , z);
//子节点再Open表中吗?
if (pOldNode = findNodeFromOpenList(nodeIndex))
{
//for(c=0;c<8;c++)
// if(pParentNode->Child[c] == NULL) /* Add Old to the list of BestNode's Children (or Successors). */
// break;
//pParentNode->Child[c]=pOldNode;
//如果新的G值比原来的更短,则改变原结点的父结点为新结点的父结点,即改变路径(只要比较g值就可以了)
if (g < pOldNode->g)
{
pOldNode->mParentNode = pParentNode;
pOldNode->g = g;
pOldNode->f = g + pOldNode->h;
}
}
else if (pOldNode = findNodeFromCloseList(nodeIndex)) //在Closed表中吗?
{
//for(c=0;c<8;c++)
// if (BestNode->Child[c] == NULL) /* Add Old to the list of BestNode's Children (or Successors). */
// break;
//BestNode->Child[c]=Old;
if (g < pOldNode->g) /* if our new g value is < Old's then reset Old's parent to point to BestNode */
{
pOldNode->mParentNode = pParentNode;
pOldNode->g = g;
pOldNode->f = g + pOldNode->h;
//第一种方式
//由于G值发生改变,所以需要重新计算该子结点周围的子结点的估价值 这样会快一些
//rehandleNode(pOldNode);
//第二种方式,从关闭列表中取出,并增加进开启列表中
findCloseNodeMoveToOpen(nodeIndex);
}
}
else
{
pSubNode = &mMapData[nodeIndex];
pSubNode->mParentNode = pParentNode;
pSubNode->g = g;
pSubNode->h = ( x - m_iEndX ) * ( x - m_iEndX ) + ( z - m_iEndZ ) * ( z - m_iEndZ );
pSubNode->f = g + pSubNode->h;
insertNodeToOpenAndOrder(pSubNode);
//for(c=0;c<8;c++)
// if (BestNode->Child[c] == NULL) /* Add Old to the list of BestNode's Children (or Successors). */
// break;
//BestNode->Child[c]=Successor;
}
}
//搜索所有子结点
void AStar::findAllSubNode(Node* pBestNode)
{
int x,z;
//上
if (hasNode(x = (int)pBestNode->x,z = (int)pBestNode->z-1))
{
handleSubNode(pBestNode,x,z);
}
//上左
if (hasNode(x = (int)pBestNode->x-1,z = (int)pBestNode->z-1))
{
handleSubNode(pBestNode,x,z);
}
//上右
if (hasNode(x = (int)pBestNode->x+1,z = (int)pBestNode->z-1))
{
handleSubNode(pBestNode,x,z);
}
//左
if (hasNode(x = (int)pBestNode->x-1,z = (int)pBestNode->z))
{
handleSubNode(pBestNode,x,z);
}
//右
if (hasNode(x = (int)pBestNode->x+1,z = (int)pBestNode->z))
{
handleSubNode(pBestNode,x,z);
}
//下
if (hasNode(x = (int)pBestNode->x,z = (int)pBestNode->z+1))
{
handleSubNode(pBestNode,x,z);
}
//下左
if (hasNode(x = (int)pBestNode->x-1,z = (int)pBestNode->z+1))
{
handleSubNode(pBestNode,x,z);
}
//下右
if (hasNode(x = (int)pBestNode->x+1,z = (int)pBestNode->z+1))
{
handleSubNode(pBestNode,x,z);
}
}