Cocos2d-x 寻路算法之二 离目的地的距离优先

原创 2013年12月05日 09:08:48

1.介绍:


Figure 1


接上一篇《Cocos2d-x 寻路算法之一 距离优先》,看这个图,我们发现这个寻路算法有点傻,明明终点在右侧却每个方向都找。难道没有其他办法了吗?从现实生活中我们知道东西如果在东边,当然是往东边搜索才是最好的办法。



2.开始动手


Figure 2


计算机中如何表示离目标近呢? 用图来解释就是这样的,目标在右上角,我们往右走,从X轴的角度来说离目标又近了一步,同理往上走是在Y轴上里目标近一步。最好的一步应该是图中-2的点,X轴和Y轴同时离目标近了一步。简单地转换成代码就是下面的这样:



bool comparebyWhichNearerGoalSimpleWay(Cell *c1, Cell *c2){
	int distanceOfC1AndGoal = abs(g_goalX - c1->getX()) + abs(g_goalY - c1->getY());
	int distanceOfC2AndGoal = abs(g_goalX - c2->getX()) + abs(g_goalY - c2->getY());
	if(distanceOfC1AndGoal <= distanceOfC2AndGoal){
		return false;
	}else{
		return true;
	}
}


扔到heap的比较条件中我们轻易地就实现了按照离目标距离优先的寻路算法,startPathFinding整个方法都不要改,只需要传进去上面提到的比较方法就行了。



    typedef bool (*compareTwoCells)(Cell *c1, Cell *c2);   
    void HelloWorld::startPathFinding(compareTwoCells compareMethod, int startX,int startY,int goalX,int goalY){  
        Cell *startCell = _m_Map.Get(startX, startY);  
        vector<Cell*> vecCells;  
        vecCells.push_back(startCell);  
        make_heap(vecCells.begin(),vecCells.end(),compareMethod);  
        startCell->setMarked(true);  
        Cell *nowProcessCell;  
      
      
        while(vecCells.size() != 0){  
            pop_heap(vecCells.begin(),vecCells.end(),compareMethod);  
            nowProcessCell = vecCells.back();  
            vecCells.pop_back();  
      
            if(nowProcessCell->getX() == _goalX && nowProcessCell->getY() == _goalY){//the goal is reach  
                return;  
            }  
      
            for(int i = 0; i < 8; ++i){ //check eight direction  
      
                int indexX = nowProcessCell->getX() + DIRECTION[i][0];  
                int indexY = nowProcessCell->getY() + DIRECTION[i][1];  
      
                if(indexX >= 0 && indexX < xLineCount && indexY >= 0 && indexY < yLineCount  
                    && _m_Map.Get(indexX,indexY)->getPassable() == true){//check is a OK cell or not  
                        Cell *cell = _m_Map.Get(indexX,indexY);  
                        float beforeDistance = DISTANCE[i] * cell->getWeight() + _m_Map.Get(nowProcessCell->getX(),  
                            nowProcessCell->getY())->getDistance();//calculate the distance  
                        if(cell->getMarked() == false){   
                            cell->setMarked(true);  
                            cell->setLastX(nowProcessCell->getX());  
                            cell->setLastY(nowProcessCell->getY());  
                            cell->setDistance(beforeDistance);  
                            vecCells.push_back(cell);//only push the unmarked cell into the vector  
                            push_heap(vecCells.begin(),vecCells.end(),compareMethod);  
                        }else{// if find a lower distance, update it   
                            if(beforeDistance < cell->getDistance()){  
                                cell->setDistance(beforeDistance);  
                                cell->setLastX(nowProcessCell->getX());  
                                cell->setLastY(nowProcessCell->getY());  
                                make_heap(vecCells.begin(),vecCells.end(),compareMethod);//distance change,so make heap again  
                            }  
                        }  
                }  
      
            }  
        }  
    }  
    startPathFinding(comparebyWhichNearerGoalSimpleWay,_playerX,_playerY,_goalX,_goalY);//demo  


3.离目的地的距离优先效果图:


Figure 3


我们惊奇地发现似乎我们成功了,就用了9步就找到了目的地!


4.算法改进


从图2中我们用的是X轴和Y轴上的相对距离,并不是真正的物理距离,意识到这个问题我们马上修改了比较函数。物理距离当然容易算了,公式如下:


换成C++函数就是下面的样子:


float distanceBetweenTwoCells(float c1X,float c1Y, float c2X, float c2Y){

	return sqrt(pow(c2X - c1X,2) + pow(c2Y - c1Y,2));
}

bool comparebyWhichNearerGoalPhysicWay(Cell *c1, Cell *c2){
	float distanceOfC1AndGoal = distanceBetweenTwoCells((float)c1->getX(),(float)c1->getY(),(float)g_goalX,(float) g_goalY);

	float distanceOfC2AndGoal = distanceBetweenTwoCells((float)c2->getX(),(float)c2->getY(),(float)g_goalX,(float) g_goalY);
	if(distanceOfC1AndGoal <= distanceOfC2AndGoal){
		return false;
	}else{
		return true;
	}
}

演示了下发现没有什么变化。但我们知道我们变的更好了。


5.该算法存在的问题


1.很容易想到的一个问题是,它没有考虑权重!如果目标在右侧,而右侧是一条非常难走的路,那么这个算法将毫无顾虑地走过去,丝毫不考虑就在不远处有条非常轻松的路。下面这个图就可以说明这个问题。



2.还有个问题,即使没有权重Cell的存在,只有可通过和不可通过Cell的存在,这个算法也有问题,我们可以人为地制造一个陷进,虽然目标在起点的下方,但是上面有条更近的路,这个算法应该会愚蠢地在往下找吧,这个就跟人一样,有时候目光短浅。下图是演示结果。


对比之前的算法发现其实上面的这条路更好的,虽然它查询了大量的Cell才发现这点(人家很努力的好不好)。




看看还有什么更好的办法没有?期待下篇的寻路算法吧。



6.项目下载


(请用7z解压,开发工具vs2010)

 http://www.waitingfy.com/?attachment_id=828



A*算法应用可以看下这篇文章《贪吃蛇 AI 的实现 snake AI

cocos2d-x学习日志(14) --A星寻路算法之45度地图

一、A星搜索 他就是一种启发性的算法,根据现在到达这个位置的步数及之后的“估计步数”,即f=g+h,f是整个从起点到终点的代价,g是从起点到我们目前位置的步数,h是从目前位置到终点的估计值,注意这...

cocos2dx 3.x 实现 A星(A*)(A-star)算法自动寻路(一)

自动寻路里面的说的最多的就是A星寻路了,但是网上找了些博客大家写的有点简略,导致对于刚接触的人来说理解的不够清楚。在这里我将用大量的图片一步一步地列出A星算法的寻路过程。A星算法对于大地图的效率不高,...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

cocos2dx 利用遮罩层来实现地图的简单寻路

谈到地图不少人都说要做地图编辑器了,但是我暂时绕过这一步,如果不用寻路地图就不能移动?寻路就是会绕过障碍物的算法。 我做了一个简单的地图的思想,就是地图分层3层:背景层、可行区域层、遮罩层,但是地图...

Cocos2d-x 3.x 练习 2 骨骼动画

其实是想到什么就是学什么啦。(又跑到骨骼动画什么鬼)。。。 PS:学习历程啦,可能会有很多错误。 骨骼动画用的是spine 的样例了。spineboy 有两个动作 jump 和 walk。 在ex...

Cocos2d-x 2.0.4 如何制作一个基于Tile的游戏(2)

转自:http://blog.csdn.net/akof1314/article/details/8492174 在第一篇《如何制作一个基于Tile的游戏》基础上,增加碰撞和拾取功能,原文《Coll...

Cocos2d-x 寻路算法之三 A Star

1.A Star 寻路算法介绍: 看过之前的两篇文章:《Cocos2d-x 寻路算法之二 离目的地的距离优先》,《Cocos2d-x 寻路算法之一 距离优先》的读者知道,这两种寻路算法都有问题,前...

菜鸟福利 A星寻路算法 cocos2d-x实现

这篇blog是翻译自iOS Tutorial Team的成员 Johann Fradj发,他目前是一位全职的资深iOS开发工程师。他是HotApps Factory的创始人,该公司开发了AppCook...

如何实现A星寻路算法 Cocos2d-x 3.0 beta2

本文实践自 Johann Fradj 的文章《How To Implement A* Pathfinding with Cocos2D Tutorial》,文中使用Cocos2D,我在这里使用Coco...
  • akof1314
  • akof1314
  • 2014年02月17日 13:50
  • 10818

如何实现A星寻路算法 Cocos2d-x 3.0 beta2

本文实践自 Johann Fradj 的文章《How To Implement A* Pathfinding with Cocos2D Tutorial》,文中使用Cocos2D,我在这里使用Coco...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Cocos2d-x 寻路算法之二 离目的地的距离优先
举报原因:
原因补充:

(最多只允许输入30个字)