zoukankan      html  css  js  c++  java
  • 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. }  
  • 相关阅读:
    springBoot 2.1.5 pom 文件 unknown 错误
    @HystrixCommand 不能被导包
    SQL数据库连接语句
    ADO.NET中COMMAND对象的ExecuteNonQuery、ExcuteReader和ExecuteScalar方法
    重载和重写的区别
    抽象类和接口的相同点和不同点
    结构详解
    简单工厂和抽象工厂的区别
    DataRead和DataSet的异同
    什么是Web Server
  • 原文地址:https://www.cnblogs.com/liuzhi/p/4036293.html
Copyright © 2011-2022 走看看