自己写的一个A星寻路类

          能用是能用,但是效率什么的就不好说了,用在客户端还可以,如果是服务器同时算成百上千个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);
 }

}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值