转自:http://blog.csdn.net/hpking/article/details/9775289
#ifndef__ASTARPATHFINDER_H__
#define__ASTARPATHFINDER_H__
#include"cocos2d.h"
USING_NS_CC;
/**
*横向移动一格的路径评分
*/
staticconstintCOST_HORIZONTAL=20;
/**
*竖向移动一格的路径评分
*/
staticconstintCOST_VERTICAL=5;
/**
*斜向移动一格的路径评分
*/
staticconstintCOST_DIAGONAL=12;
classPathInfo;
/**
*A星寻路类
*@authorhpking
*
*/
classAStarPathFinder{
//未探索的节点列表 cocos2d::CCArray*_openSteps; //已探索的,不需要再寻路的节点列表 CCArray*_closedSteps;
//地图相关数据 PathInfo*_pathInfo;
public: AStarPathFinder(PathInfo*info); virtual~AStarPathFinder();
/**
*public寻路
*
*@paramCCPointstartPointtile开始坐标点
*@paramCCPointendPointtile结束坐标点
*@returnCCArray*读取方法:CCPointFromString(string->getCString())
*/
CCArray*find(CCPointstartTilePt,CCPointendTilePt);
private: //最短路径步数 classShortestPathStep:publicCCObject { public: boolinitWithPosition(CCPointpos) { boolbRet=false;
do { position=pos; gscore=0; hscore=0; parent=NULL; inOpen=false; inClose=false;
bRet=true; } while(0);
returnbRet; }
intfscore() { returnthis->getGscore()+this->getHscore(); }
inlinebooloperator==(constShortestPathStep*other) { returnisEqual(other); }
boolisEqual(constShortestPathStep*other) { returnthis->getPosition().equals(other->getPosition()); }
staticShortestPathStep*inst(CCPointpos) { AStarPathFinder::ShortestPathStep*sps=newShortestPathStep;
if(sps&&sps->initWithPosition(pos)) { sps->autorelease(); returnsps; }
CC_SAFE_DELETE(sps); returnNULL; }
CC_SYNTHESIZE(CCPoint,position,Position); CC_SYNTHESIZE(int,gscore,Gscore); hscore,Hscore); ShortestPathStep*,parent,Parent); CC_SYNTHESIZE(bool,inOpen,InOpen); inClose,InClose);
private: CCString*description() { returnCCString::createWithFormat("pos=[%f,%f],g=%d,h=%d,f=%d",this->getPosition().x,0)">getPosition().y,0)">getGscore(),0)">getHscore(),0)">fscore()); } };
private: voiddestroyLists();
createPath(ShortestPathStep*step);//intxStart,intyStart voidfindAndSort(ShortestPathStep*step);
voidinsertAndSort(ShortestPathStep*step);
/**
*private判断是否超出边界或路点是否可走
*
*@paramCCPointtpt
*@returnbool
*/
boolisWalkable(CCPointtpt);
/**
*private计算G值
*
*@paramNode*curNode
*@paramNode*node
*@returnint
*/
intgetGValue(ShortestPathStep*curStep,133)">ShortestPathStep*step);
/**
*private计算H值
*
*@paramNode*curNode
*@paramNode*endNode
*@paramNode*node
*@returnint
*/
intgetHValue(ShortestPathStep*endStep,133)">ShortestPathStep*step);
getAroundsNode(CCPointtPt);
boolisInClosed(CCPointtPt);
voidsetOpenSteps(CCArray*var); voidsetClosedSteps(setShortestPath(CCArray*var);};
#endif
#include"AStarPathFinder.h" #include"map/PathInfo.h"
PathInfo*info){
_pathInfo=info; _openSteps=NULL; _closedSteps=NULL;}
AStarPathFinder::~AStarPathFinder(){
destroyLists();}
//获取毫秒时间
longmsNow(){
structcc_timevalnow; CCTime::gettimeofdayCocos2d(&now,NULL); return(now.tv_sec*1000+now.tv_usec/1000);}
CCArray*AStarPathFinder::CCPointendTilePt){
boolisFinded=false;//能否找到路径,true-已找到
//到达终点
if(startTilePt.equals(endTilePt)){
CCLog("You'realreadythere!:P"); returnNULL;}
//终点不可走,直接退出(可优化为最近的可走地点停止)
if(!isWalkable(endTilePt)){
"blocked!:P"); returnNULL;}
//设置打开和封闭步数
CCArray::create()); create());
//CCLog("From:(%f,%f)To(%f,%f)",startTilePt.x,startTilePt.y,endTilePt.x,endTilePt.y);
//结束坐标
ShortestPathStep*endStep=ShortestPathStep::inst(endTilePt);
//插入开始点
inst(startTilePt));
ShortestPathStep*curStep; longtime1=msNow();
do
{
//取出并删除开放列表第一个元素
curStep=(ShortestPathStep*)_openSteps->objectAtIndex(0); curStep->setInClose(true); curStep->setInOpen(false); _closedSteps->addObject(curStep); _openSteps->removeObjectAtIndex(0);
//当前节点==目标节点
if(curStep->equals(endTilePt)){
isFinded=true;//能达到终点,找到路径 break;}
//取相邻八个方向的节点,去除不可通过和已在关闭列表中的节点
CCArray*aroundNodes=getAroundsNode(curStep->getPosition());//CCLog("8dirc%d",aroundNodes->count());
CCObject*obj; CCARRAY_FOREACH(aroundNodes,obj){
//计算G,H值
CCString*string=(CCString*)obj; ShortestPathStep*nextStep=newShortestPathStep; nextStep->initWithPosition(CCPointFromString(string->getCString()));
intg=getGValue(curStep,nextStep); inth=getHValue(curStep,endStep,nextStep);
if(nextStep->getInOpen())//如果节点已在播放列表中{
//如果该节点新的G值比原来的G值小,修改F,G值,设置该节点的父节点为当前节点
if(g<nextStep->getGscore()){
nextStep->setGscore(g); nextStep->setHscore(h); nextStep->setParent(curStep); findAndSort(nextStep); nextStep->release();}
}
else//如果节点不在开放列表中{
//插入开放列表中,并按照估价值排序
nextStep->setParent(curStep);
insertAndSort(nextStep); nextStep->release();}
//CCLog("opennum:%d",_openSteps->count());
}
}
while(_openSteps->count()>0);
"a*time:%d",0)">msNow()-time1);
/*if(_openSteps)
CCLog("finded:%d,openlen%d,closelen%d",isFinded?1:0,_openSteps->count(),_closedSteps->count());*/
//找到路径
if(isFinded){
CCArray*path=createPath(curStep);
destroyLists();
returnpath;}
else//没有找到路径{
destroyLists();
returnNULL;}
}
voiddestroyLists(){
CC_SAFE_RELEASE_NULL(_openSteps); CC_SAFE_RELEASE_NULL(_closedSteps);}
ShortestPathStep*step)//intxStart,intyStart{
CCArray*path=create();
CCString*str;
do
{
if(step->getParent()!=NULL){
str="{%f,%f}",step->getPosition().y); path->insertObject(str,0);}
step=step->getParent();}
while(step!=NULL);
returnpath;}
voidShortestPathStep*step){
unsignedintcount=_openSteps->count();
if(count<1) return;
intstepFscore=step->fscore();
for(unsignedinti=0;i<count;i++){
ShortestPathStep*sps=(objectAtIndex(i);
if(stepFscore<=sps->fscore()) _openSteps->insertObject(step,i);
if(step->equals(sps->getPosition())) _openSteps->removeObjectAtIndex(i);}
}
voidShortestPathStep*step){
step->setInOpen(true);
intstepFscore=step->fscore(); unsignedintcount=_openSteps->count();
if(count==0) _openSteps->addObject(step);else
{
for(unsignedinti=0;i<count;i++){
fscore()){
_openSteps->i); return;}
}
}
}
boolCCPointtPt){
//1.是否是有效的地图上点(数组边界检查)
if(tPt.x<_pathInfo->startPt.x||tPt.x>=_pathInfo->iCol) returnfalse;
if(tPt.y<_pathInfo->startPt.y||tPt.y>=_pathInfo->iRow) returnfalse;
//2.是否是walkable
return_pathInfo->isWalkable(tPt);}
/**
*private计算G值
*
*@paramShortestPathStep*curStep
*@paramShortestPathStep*step
*@returnint
*/
intShortestPathStep*step){
intg=0;
if(curStep->getPosition().y==step->getPosition().y)//横向左右{
g=curStep->getGscore()+COST_HORIZONTAL;}
elseif(curStep->getPosition().y+2==step->getPosition().y||curStep->getPosition().y-2==step->getPosition().y)//竖向上下{
g=curStep->getGscore()+COST_VERTICAL*2;}
else//斜向左上左下右上右下{
g=curStep->getGscore()+COST_DIAGONAL;}
returng;}
/**
*private计算H值
*
*@paramShortestPathStep*curStep
*@paramShortestPathStep*endStep
*@paramShortestPathStep*step
*@returnint
*/
intShortestPathStep*step){
if(curStep==NULL||endStep==NULL||step==NULL) return0;
//节点到0,0点的x轴距离
intto0=step->getPosition().x*COST_HORIZONTAL+((int)step->getPosition().y&1)*COST_HORIZONTAL/2;
//终止节点到0,0点的x轴距离
intendTo0=endStep->getPosition().x*COST_HORIZONTAL+((int)endStep->getPosition().y&1)*COST_HORIZONTAL/2;
returnabs((float)endTo0-(float)to0)+abs((float)endStep->getPosition().y-(float)step->getPosition().y)*COST_VERTICAL;}
CCPointtPt){
CCArray*aroundNodes=create();
///菱形组合的地图八方向与正常不同
//左
CCPointp=CCPointMake(tPt.x-1,tPt.y); CCString*str;
if(isWalkable(p)&&!isInClosed(p))//可走并且不在关闭列表{
str=p.x,p.y);//CCLOG("left=%s",str->getCString());
aroundNodes->addObject(str);}
//右
p=CCPointMake(tPt.x+1,tPt.y);
if(isInClosed(p)){
str=p.y); //CCLOG("right=%s",0)">addObject(str);}
//上
p=CCPointMake(tPt.x,tPt.y-2);//-2
if(p.y); //CCLOG("up=%s",0)">addObject(str);}
//下
p=tPt.y+2);//+2
if(p.y); //CCLOG("down=%s",0)">addObject(str);}
//左上
p=CCPointMake(tPt.x-1+((int)tPt.y&1),tPt.y-1);
if(p.y); //CCLOG("leftUp=%s",0)">addObject(str);}
//左下
p=tPt.y+1);
if(p.y); //CCLOG("leftDown=%s",0)">addObject(str);}
//右上
p=CCPointMake(tPt.x+((int)tPt.y&1),p.y); //CCLOG("rightUp=%s",0)">addObject(str);}
//右下
p=p.y); //CCLOG("rightDown=%s",0)">addObject(str);}
returnaroundNodes;}
boolCCPointpt){
CCObject*temp; CCARRAY_FOREACH(_closedSteps,temp){
ShortestPathStep*)temp;
if(sps->equals(pt)){
returntrue;}
}
returnfalse;}
voidCCArray*var){
if(_openSteps!=var){
CC_SAFE_RETAIN(var); _openSteps=var;}
}
voidCCArray*var){
if(_closedSteps!=var){
CC_SAFE_RELEASE_NULL(_closedSteps); CC_SAFE_RETAIN(var); _closedSteps=var;}
}
voidCCArray*var){
/*if(shortestPath!=var)
{
CC_SAFE_RELEASE_NULL(shortestPath);
CC_SAFE_RETAIN(var);
shortestPath=var;
}*/
}