cocos2dx A* + tiledMap

本文转自:http://blog.csdn.net/w18767104183/article/category/1757765

前面一章讲了cocos2dx 中使用A星算法

这章中讲 A*结合tiledmap

先看下效果图

图有点丑,忍受下

绿色的块 表示人物的行走的路线(A*算法的结果)

红色部分 表示A*算法搜寻过的点(越少,速度越快)

黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物

 

这张图是用tiledmap做出来的, 看看里面的内容

可以看到 我把不能通过的地区的图块给删了

tiledmap中有2个层 一个是background, 一个是road. 为了方便, 我把road也用同样的图片, 最好的方法是用一种同样的瓦片拼接出来一条能走的路, 让后把background图层加到road图层上就ok了.

下面直接上源码, 用的时cocos2.2.3, 拷贝到项目中就能用了.当然别忘了自己做个像样的tiledMap . 

 如果你觉得好用, 就在文章底下顶一个吧 , enjoy it !

 

[cpp] view plaincopy
 
  1. #ifndef __HELLOWORLD_SCENE_H__  
  2. #define __HELLOWORLD_SCENE_H__  
  3.   
  4. #include "cocos2d.h"  
  5. #include "vector"  
  6. using namespace std;  
  7. USING_NS_CC;  
  8. #define MAP_WIDTH 200//要比tmx中的map大  
  9. #define MAP_HEIGHT 200  
  10. class PathSprite   
  11. {  
  12. public:  
  13.     PathSprite(CCSprite* sprite)  
  14.     {  
  15.         m_parent = NULL;  
  16.         m_child = NULL;  
  17.         m_costToSource = 0;  
  18.         m_FValue = 0;  
  19.         m_sprite = sprite;  
  20.     };  
  21. public:  
  22.     CCSprite* m_sprite;//包含的瓦片精灵  
  23.     PathSprite* m_parent;//父节点  
  24.     PathSprite* m_child;//子节点  
  25.     float m_costToSource;//到起始点的距离  
  26.     int m_x;//地图坐标  
  27.     int m_y;  
  28.     float m_FValue;  
  29. };  
  30. class PathSearchInfo//寻路类(主要负责寻路的参数和逻辑)  
  31. {  
  32. public:  
  33.       
  34.     static int m_startX;//开始点  
  35.     static int m_startY;  
  36.       
  37.     static int m_endX;//结束点  
  38.     static int m_endY;  
  39.    
  40.     static CCSize m_mapSize;//地图大小  
  41.     static CCSize m_tileSize;//地图的块大小  
  42.     static vector<PathSprite*> m_openList;//开放列表(里面存放相邻节点)  
  43.     static PathSprite* m_inspectArray[MAP_WIDTH][MAP_HEIGHT];//全部需要检测的点  
  44.     static vector<PathSprite*> m_pathList;//路径列表  
  45.     static vector<PathSprite*> m_haveInspectList;//检测过的列表  
  46.   
  47.     static float calculateTwoObjDistance(PathSprite* obj1, PathSprite* obj2)//计算两个物体间的距离  
  48.     {  
  49.         //        float _offsetX = obj1->m_x - obj2->m_x;  
  50.         //        float _offsetY = obj1->m_y - obj2->m_y;  
  51.         //        return sqrt( _offsetX * _offsetX + _offsetY * _offsetY);  
  52.           
  53.         float _x = abs(obj2->m_x - obj1->m_x);  
  54.         float _y = abs(obj2->m_y - obj1->m_y);  
  55.           
  56.         return _x + _y;  
  57.     }  
  58.     static void inspectTheAdjacentNodes(PathSprite* node, PathSprite* adjacent, PathSprite* endNode)//把相邻的节点放入开放节点中  
  59.     {  
  60.         if (adjacent)  
  61.         {  
  62.             float _x = abs(endNode->m_x - adjacent->m_x);  
  63.             float _y = abs(endNode->m_y - adjacent->m_y);  
  64.               
  65.             float F , G, H1, H2, H3;  
  66.             adjacent->m_costToSource = node->m_costToSource + calculateTwoObjDistance(node, adjacent);//获得累计的路程  
  67.             G = adjacent->m_costToSource;  
  68.               
  69.             //三种算法, 感觉H2不错  
  70.             H1 = _x + _y;  
  71.             H2 = hypot(_x, _y);  
  72.             H3 = max(_x, _y);  
  73.               
  74. #if 1 //A*算法 = Dijkstra算法 + 最佳优先搜索  
  75.             F = G + H2;  
  76. #endif  
  77. #if 0//Dijkstra算法  
  78.             F = G;  
  79. #endif  
  80. #if 0//最佳优先搜索  
  81.             F = H2;  
  82. #endif  
  83.             adjacent->m_FValue = F;  
  84.               
  85.             adjacent->m_parent = node;//设置父节点  
  86.             adjacent->m_sprite->setColor(ccORANGE);//搜寻过的节点设为橘色(测试用)  
  87.             m_haveInspectList.push_back(adjacent);  
  88.             node->m_child = adjacent;//设置子节点  
  89.   
  90.             PathSearchInfo::m_inspectArray[adjacent->m_x][adjacent->m_y] = NULL;//把检测过的点从检测列表中删除  
  91.             PathSearchInfo::m_openList.push_back(adjacent);//加入开放列表  
  92.         }  
  93.     }  
  94.     static PathSprite* getMinPathFormOpenList()//从开放节点中获取F值最小值的点  
  95.     {  
  96.         if (m_openList.size()>0) {  
  97.             PathSprite* _sp =* m_openList.begin();  
  98.             for (vector<PathSprite*>::iterator iter = m_openList.begin(); iter !=  m_openList.end(); iter++)  
  99.             {  
  100.                 if ((*iter)->m_FValue < _sp->m_FValue)  
  101.                 {  
  102.                     _sp = *iter;  
  103.                 }  
  104.             }  
  105.             return _sp;  
  106.         }  
  107.         else  
  108.         {  
  109.             return NULL;  
  110.         }  
  111.           
  112.     }  
  113.     static PathSprite* getObjFromInspectArray(int x, int y)//根据横纵坐标从检测数组中获取点  
  114.     {  
  115.         if (x >=0 && y >=0 && x < m_mapSize.width && y < m_mapSize.height) {  
  116.             return m_inspectArray[x][y];  
  117.         }  
  118.         return  NULL;  
  119.     }  
  120.     static bool removeObjFromOpenList( PathSprite* sprite)//从开放列表中移除对象  
  121.     {  
  122.         if (!sprite) {  
  123.             return  false;  
  124.         }  
  125.         for (vector<PathSprite*>::iterator iter = m_openList.begin(); iter !=  m_openList.end(); iter++)  
  126.         {  
  127.             if (*iter == sprite)  
  128.             {  
  129.                 m_openList.erase(iter);  
  130.                 return true;  
  131.             }  
  132.         }  
  133.         return false;  
  134.           
  135.     }    
  136. };  
  137. class HelloWorld : public cocos2d::CCLayer  
  138. {  
  139. public:  
  140.     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone  
  141.     virtual bool init();    
  142.   
  143.     // there's no 'id' in cpp, so we recommend returning the class instance pointer  
  144.     static cocos2d::CCScene* scene();  
  145.       
  146.     // a selector callback  
  147.     void menuCloseCallback(CCObject* pSender);  
  148.       
  149.     // implement the "static node()" method manually  
  150.     CREATE_FUNC(HelloWorld);  
  151.     void onEnter();  
  152.     virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);  
  153.     virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);  
  154.     virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);  
  155.       
  156.     void calculatePath();//计算路径  
  157.       
  158.     void drawPath();//绘制路径(测试用)  
  159.       
  160.     void clearPath();//清理路径  
  161.   
  162.     void playerMove();//人物走动  
  163.   
  164.     void update(float dt);//跟新大地图(行走时, 人不动, 地图跟着人动);  
  165.       
  166. public:  
  167.     CCPoint m_orignPoint;//人物的起始点  
  168.       
  169.     PathSprite* m_player;//人物点  
  170.       
  171.     int m_playerMoveStep;//人物当前的行程的索引  
  172.       
  173. };  
  174.   
  175. #endif // __HELLOWORLD_SCENE_H__  
[cpp] view plaincopy
 
  1. #include "HelloWorldScene.h"  
  2.   
  3. USING_NS_CC;  
  4. vector<PathSprite*> PathSearchInfo::m_openList;  
  5.   
  6. PathSprite* PathSearchInfo::m_inspectArray[MAP_WIDTH][MAP_HEIGHT] = {NULL};  
  7.   
  8. vector<PathSprite*> PathSearchInfo::m_pathList;  
  9.   
  10. vector<PathSprite*> PathSearchInfo::m_haveInspectList;  
  11.   
  12. CCSize PathSearchInfo::m_mapSize;  
  13.   
  14. CCSize PathSearchInfo::m_tileSize;  
  15.   
  16. int PathSearchInfo::m_startX;  
  17.   
  18. int PathSearchInfo::m_startY;  
  19.   
  20. int PathSearchInfo::m_endX;  
  21.   
  22. int PathSearchInfo::m_endY;  
  23.   
  24. CCScene* HelloWorld::scene()  
  25. {  
  26.     // 'scene' is an autorelease object  
  27.     CCScene *scene = CCScene::create();  
  28.       
  29.     // 'layer' is an autorelease object  
  30.     HelloWorld *layer = HelloWorld::create();  
  31.   
  32.     // add layer as a child to scene  
  33.     scene->addChild(layer);  
  34.   
  35.     // return the scene  
  36.     return scene;  
  37. }  
  38.   
  39. // on "init" you need to initialize your instance  
  40. void HelloWorld::onEnter()  
  41. {  
  42.     CCDirector* pDirector = CCDirector::sharedDirector();  
  43.     pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);  
  44.     CCLayer::onEnter();  
  45.   
  46. }  
  47.   
  48. bool HelloWorld::init()  
  49. {  
  50.     //////////////////////////////  
  51.     // 1. super init first  
  52.     if ( !CCLayer::init() )  
  53.     {  
  54.         return false;  
  55.     }  
  56.       
  57.     CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();  
  58.     CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();  
  59.   
  60.     /////////////////////////////  
  61.     // 2. add a menu item with "X" image, which is clicked to quit the program  
  62.     //    you may modify it.  
  63.   
  64.   
  65.       
  66.     CCLabelTTF* pLabel = CCLabelTTF::create("A* + tiledMap", "Arial", 24);  
  67.       
  68.     // position the label on the center of the screen  
  69.     pLabel->setPosition(ccp(origin.x + visibleSize.width/2,  
  70.                             origin.y + visibleSize.height - pLabel->getContentSize().height));  
  71.   
  72.     // add the label as a child to this layer  
  73.     this->addChild(pLabel, 1);  
  74.   
  75.     this->scheduleUpdate();  
  76.   
  77.    CCTMXTiledMap* map = CCTMXTiledMap::create("gameMap.tmx");  
  78.     this->addChild(map);  
  79.     map->setPosition(CCPoint());  
  80.     CCTMXLayer* _road = map->layerNamed("road");//行走路径的地图  
  81.     CCSize _mapSize = map->getMapSize();  
  82.     for (int j = 0;  j < _mapSize.height; j++) {  
  83.         for (int i = 0;  i < _mapSize.width; i++) {  
  84.             CCSprite* _sp = _road->tileAt(CCPoint(i, j));  
  85.             if (_sp) {  
  86.                 PathSprite* _pathSprite = new PathSprite(_sp);  
  87.                 _pathSprite->m_x = i;  
  88.                 _pathSprite->m_y = j;  
  89.                 PathSearchInfo::m_inspectArray[i][j] = _pathSprite;//把地图中所有的点一一对应放入检测列表中  
  90.             }  
  91.         }  
  92.     }  
  93.     PathSearchInfo::m_mapSize = _mapSize;//获取地图的尺寸  
  94.     PathSearchInfo::m_tileSize = map->getTileSize();//获取瓦片的尺寸  
  95.       
  96.     //设置起始和终点  
  97.     PathSearchInfo::m_startX =30;  
  98.     PathSearchInfo::m_startY = 75;  
  99.   
  100.     //创建一个人物  
  101.     m_player = new PathSprite(CCSprite::create("10001.png"));  
  102.     m_player->m_sprite->setAnchorPoint(CCPoint(0.5,0));  
  103.     this->addChild(m_player->m_sprite);  
  104.       
  105.     m_player->m_x = PathSearchInfo::m_startX;//设置人物的起始的地图坐标  
  106.     m_player->m_y = PathSearchInfo::m_startY;  
  107.       
  108.     m_orignPoint = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY]->m_sprite->getPosition();  
  109.     m_player->m_sprite->setPosition(m_orignPoint);//设置人物的起始的世界坐标  
  110.   
  111.       
  112.       
  113.     return true;  
  114. }  
  115. void HelloWorld::calculatePath()  
  116. {  
  117.       
  118.     //得到开始点的节点  
  119.     PathSprite* _startNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY];  
  120.     //得到结束点的节点  
  121.     PathSprite* _endNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_endX][PathSearchInfo::m_endY];  
  122.       
  123.     //因为是开始点 把到起始点的距离设为0, F值也为0  
  124.     _startNode->m_costToSource = 0;  
  125.     _startNode->m_FValue = 0;  
  126.       
  127.     //把已经检测过的点从检测列表中删除  
  128.     PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY] = NULL;  
  129.     //把该点放入已经检测过点的列表中  
  130.     PathSearchInfo::m_haveInspectList.push_back(_startNode);  
  131.     //然后加入开放列表  
  132.     PathSearchInfo::m_openList.push_back(_startNode);  
  133.       
  134.     PathSprite* _node = NULL;  
  135.     while (true)  
  136.     {  
  137.         //得到离起始点最近的点(如果是第一次执行, 得到的是起点)  
  138.         _node = PathSearchInfo::getMinPathFormOpenList();  
  139.         if (!_node)  
  140.         {  
  141.             //找不到路径  
  142.             break;  
  143.         }  
  144.         //把计算过的点从开放列表中删除  
  145.         PathSearchInfo::removeObjFromOpenList( _node);  
  146.         int _x = _node->m_x;  
  147.         int _y = _node->m_y;  
  148.           
  149.         //  
  150.         if (_x ==PathSearchInfo::m_endX && _y == PathSearchInfo::m_endY)  
  151.         {  
  152.             break;  
  153.         }  
  154.           
  155.         //检测8个方向的相邻节点是否可以放入开放列表中  
  156.         CCLog("%d, %d",_x, _y);  
  157.         PathSprite* _adjacent = PathSearchInfo::getObjFromInspectArray( _x + 1, _y + 1);  
  158.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  159.           
  160.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x +1, _y);  
  161.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  162.           
  163.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x +1, _y-1);  
  164.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  165.           
  166.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x , _y -1);  
  167.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  168.           
  169.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x -1, _y - 1);  
  170.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  171.           
  172.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x -1, _y);  
  173.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  174.           
  175.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x -1, _y+1);  
  176.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  177.           
  178.         _adjacent = PathSearchInfo::getObjFromInspectArray(  _x , _y+1);  
  179.         PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);  
  180.           
  181.     }  
  182.       
  183.     while (_node)  
  184.     {  
  185.         //把路径点加入到路径列表中  
  186.         PathSearchInfo::m_pathList.insert(PathSearchInfo::m_pathList.begin(), _node);  
  187.         _node = _node->m_parent;  
  188.     }  
  189. }  
  190.   
  191.   
  192. void HelloWorld::drawPath(  )  
  193. {  
  194.     for (vector<PathSprite*>::iterator iter = PathSearchInfo::m_pathList.begin(); iter !=  PathSearchInfo::m_pathList.end(); iter++)  
  195.     {  
  196.         (*iter)->m_sprite->setColor(ccGREEN);  
  197.     }  
  198.       
  199. }  
  200. CCRect getBoundingBox(float x, float y, float width, float height)  
  201. {  
  202.     return CCRect(x - width/2, y - height/2, width, height);  
  203. }  
  204. bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)  
  205. {  
  206.   
  207.     //清除之前的路径  
  208.     clearPath();  
  209.       
  210.     auto nodePosition = convertToNodeSpace( touch->getLocation() );  
  211.     CCLog("%f, %f", nodePosition.x, nodePosition.y);  
  212. //    for (int i = 0; i < PathSearchInfo::m_inspectList.size(); i++)  
  213. //    {  
  214. //        PathSprite* _sp = PathSearchInfo::m_inspectList[i];  
  215. //          
  216. //        CCRect _rect = getBoundingBox( _sp->m_sprite->getPositionX(), _sp->m_sprite->getPositionY(), _sp->m_sprite->getContentSize().width, _sp->m_sprite->getContentSize().height);  
  217. //          
  218. //        if (_rect.containsPoint(nodePosition))  
  219. //        {  
  220.     PathSprite* _sp = PathSearchInfo::m_inspectArray[(int)(nodePosition.x/PathSearchInfo::m_tileSize.width)][(int)(PathSearchInfo::m_mapSize.height - nodePosition.y/PathSearchInfo::m_tileSize.height)];  
  221.     if (_sp) {  
  222.         CCLog("%f, %f", _sp->m_sprite->getPositionX(), _sp->m_sprite->getPositionY());  
  223.         //获取触摸点, 设置为终点  
  224.         PathSearchInfo::m_endX = _sp->m_x;  
  225.         PathSearchInfo::m_endY = _sp->m_y;  
  226.         //计算路径  
  227.         calculatePath();  
  228.         //绘制路径  
  229.         drawPath(  );  
  230.         //移动物体  
  231.         playerMove();  
  232.     }  
  233.       
  234.       
  235. //        }  
  236. //          
  237. //    }  
  238.   
  239.     return true;  
  240. }  
  241.   
  242. void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)  
  243. {  
  244.   
  245. }  
  246.   
  247.   
  248.   
  249. void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)  
  250. {  
  251.   
  252. }  
  253.   
  254. void HelloWorld::menuCloseCallback(CCObject* pSender)  
  255. {  
  256. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)  
  257.     CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");  
  258. #else  
  259.     CCDirector::sharedDirector()->end();  
  260. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
  261.     exit(0);  
  262. #endif  
  263. #endif  
  264. }  
  265.   
  266. void HelloWorld::clearPath()  
  267. {  
  268.     for (vector<PathSprite*>::iterator iter = PathSearchInfo::m_haveInspectList.begin(); iter !=  PathSearchInfo::m_haveInspectList.end(); iter++)  
  269.     {  
  270.         (*iter)->m_sprite->setColor(ccWHITE);  
  271.         (*iter)->m_costToSource = 0;  
  272.         (*iter)->m_FValue = 0;  
  273.         (*iter)->m_parent = NULL;  
  274.         (*iter)->m_child = NULL;  
  275.           
  276.         PathSearchInfo::m_inspectArray[(*iter)->m_x][(*iter)->m_y] = (*iter);  
  277.     }  
  278.       
  279.     //把移除了障碍物的地图放入检测列表中  
  280.     //PathSearchInfo::m_inspectList = PathSearchInfo::m_mapList;  
  281.     PathSearchInfo::m_openList.clear();  
  282.     PathSearchInfo::m_pathList.clear();  
  283.     PathSearchInfo::m_haveInspectList.clear();  
  284.     PathSearchInfo::m_startX = m_player->m_x;  
  285.     PathSearchInfo::m_startY = m_player->m_y;  
  286.     m_player->m_sprite->stopAllActions();  
  287.       
  288.     m_playerMoveStep = 0;  
  289. }  
  290.   
  291. void HelloWorld::playerMove()  
  292. {  
  293.     m_playerMoveStep++;  
  294.       
  295.     if (m_playerMoveStep >= PathSearchInfo::m_pathList.size()) {  
  296.         return;  
  297.     }  
  298.       
  299.     m_player->m_x = PathSearchInfo::m_pathList[m_playerMoveStep]->m_x;  
  300.     m_player->m_y = PathSearchInfo::m_pathList[m_playerMoveStep]->m_y;  
  301.       
  302.     //根据路径列表移动人物  
  303.     m_player->m_sprite->runAction(CCSequence::create(CCMoveTo::create(1/24.0, PathSearchInfo::m_pathList[m_playerMoveStep]->m_sprite->getPosition()), CCCallFunc::create(this, SEL_CallFunc(&HelloWorld::playerMove)) , NULL));  
  304.       
  305. }  
  306. void HelloWorld::update(float dt)  
  307. {  
  308.     this->setPosition(m_orignPoint - m_player->m_sprite->getPosition());  
  309. }  
posted @ 2014-10-20 00:28  修行,波动线  阅读(321)  评论(0编辑  收藏  举报