最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

cocos2dxA*+tiledMap

来源:动视网 责编:小采 时间:2020-11-09 15:29:02
文档

cocos2dxA*+tiledMap

cocos2dxA*+tiledMap:前面一章讲了cocos2dx 中使用A星算法 这章中讲 A*结合tiledmap 先看下效果图 图有点丑,忍受下 绿色的块 表示人物的行走的路线(A*算法的结果) 红色部分 表示A*算法搜寻过的点(越少,速度越快) 黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物 这张图
推荐度:
导读cocos2dxA*+tiledMap:前面一章讲了cocos2dx 中使用A星算法 这章中讲 A*结合tiledmap 先看下效果图 图有点丑,忍受下 绿色的块 表示人物的行走的路线(A*算法的结果) 红色部分 表示A*算法搜寻过的点(越少,速度越快) 黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物 这张图


前面一章讲了cocos2dx 中使用A星算法 这章中讲 A*结合tiledmap 先看下效果图 图有点丑,忍受下 绿色的块 表示人物的行走的路线(A*算法的结果) 红色部分 表示A*算法搜寻过的点(越少,速度越快) 黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物 这张图是

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

这章中讲 A*结合tiledmap

先看下效果图


图有点丑,忍受下

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

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

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


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


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

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

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

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

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "vector"
using namespace std;
USING_NS_CC;
#define MAP_WIDTH 200//要比tmx中的map大
#define MAP_HEIGHT 200
class PathSprite 
{
public:
 PathSprite(CCSprite* sprite)
 {
 m_parent = NULL;
 m_child = NULL;
 m_costToSource = 0;
 m_FValue = 0;
 m_sprite = sprite;
 };
public:
 CCSprite* m_sprite;//包含的瓦片精灵
 PathSprite* m_parent;//父节点
 PathSprite* m_child;//子节点
 float m_costToSource;//到起始点的距离
 int m_x;//地图坐标
 int m_y;
 float m_FValue;
};
class PathSearchInfo//寻路类(主要负责寻路的参数和逻辑)
{
public:
 
 static int m_startX;//开始点
 static int m_startY;
 
 static int m_endX;//结束点
 static int m_endY;
 
 static CCSize m_mapSize;//地图大小
 static CCSize m_tileSize;//地图的块大小
 static vector m_openList;//开放列表(里面存放相邻节点)
 static PathSprite* m_inspectArray[MAP_WIDTH][MAP_HEIGHT];//全部需要检测的点
 static vector m_pathList;//路径列表
 static vector m_haveInspectList;//检测过的列表

 static float calculateTwoObjDistance(PathSprite* obj1, PathSprite* obj2)//计算两个物体间的距离
 {
 // float _offsetX = obj1->m_x - obj2->m_x;
 // float _offsetY = obj1->m_y - obj2->m_y;
 // return sqrt( _offsetX * _offsetX + _offsetY * _offsetY);
 
 float _x = abs(obj2->m_x - obj1->m_x);
 float _y = abs(obj2->m_y - obj1->m_y);
 
 return _x + _y;
 }
 static void inspectTheAdjacentNodes(PathSprite* node, PathSprite* adjacent, PathSprite* endNode)//把相邻的节点放入开放节点中
 {
 if (adjacent)
 {
 float _x = abs(endNode->m_x - adjacent->m_x);
 float _y = abs(endNode->m_y - adjacent->m_y);
 
 float F , G, H1, H2, H3;
 adjacent->m_costToSource = node->m_costToSource + calculateTwoObjDistance(node, adjacent);//获得累计的路程
 G = adjacent->m_costToSource;
 
 //三种算法, 感觉H2不错
 H1 = _x + _y;
 H2 = hypot(_x, _y);
 H3 = max(_x, _y);
 
#if 1 //A*算法 = Dijkstra算法 + 最佳优先搜索
 F = G + H2;
#endif
#if 0//Dijkstra算法
 F = G;
#endif
#if 0//最佳优先搜索
 F = H2;
#endif
 adjacent->m_FValue = F;
 
 adjacent->m_parent = node;//设置父节点
 adjacent->m_sprite->setColor(ccORANGE);//搜寻过的节点设为橘色(测试用)
 m_haveInspectList.push_back(adjacent);
 node->m_child = adjacent;//设置子节点

 PathSearchInfo::m_inspectArray[adjacent->m_x][adjacent->m_y] = NULL;//把检测过的点从检测列表中删除
 PathSearchInfo::m_openList.push_back(adjacent);//加入开放列表
 }
 }
 static PathSprite* getMinPathFormOpenList()//从开放节点中获取F值最小值的点
 {
 if (m_openList.size()>0) {
 PathSprite* _sp =* m_openList.begin();
 for (vector::iterator iter = m_openList.begin(); iter != m_openList.end(); iter++)
 {
 if ((*iter)->m_FValue < _sp->m_FValue)
 {
 _sp = *iter;
 }
 }
 return _sp;
 }
 else
 {
 return NULL;
 }
 
 }
 static PathSprite* getObjFromInspectArray(int x, int y)//根据横纵坐标从检测数组中获取点
 {
 if (x >=0 && y >=0 && x < m_mapSize.width && y < m_mapSize.height) {
 return m_inspectArray[x][y];
 }
 return NULL;
 }
 static bool removeObjFromOpenList( PathSprite* sprite)//从开放列表中移除对象
 {
 if (!sprite) {
 return false;
 }
 for (vector::iterator iter = m_openList.begin(); iter != m_openList.end(); iter++)
 {
 if (*iter == sprite)
 {
 m_openList.erase(iter);
 return true;
 }
 }
 return false;
 
 } 
};
class HelloWorld : public cocos2d::CCLayer
{
public:
 // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
 virtual bool init(); 

 // there's no 'id' in cpp, so we recommend returning the class instance pointer
 static cocos2d::CCScene* scene();
 
 // a selector callback
 void menuCloseCallback(CCObject* pSender);
 
 // implement the "static node()" method manually
 CREATE_FUNC(HelloWorld);
 void onEnter();
 virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
 virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
 virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
 
 void calculatePath();//计算路径
 
 void drawPath();//绘制路径(测试用)
 
 void clearPath();//清理路径

 void playerMove();//人物走动

 void update(float dt);//跟新大地图(行走时, 人不动, 地图跟着人动);
 
public:
 CCPoint m_orignPoint;//人物的起始点
 
 PathSprite* m_player;//人物点
 
 int m_playerMoveStep;//人物当前的行程的索引
 
};

#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"

USING_NS_CC;
vector PathSearchInfo::m_openList;

PathSprite* PathSearchInfo::m_inspectArray[MAP_WIDTH][MAP_HEIGHT] = {NULL};

vector PathSearchInfo::m_pathList;

vector PathSearchInfo::m_haveInspectList;

CCSize PathSearchInfo::m_mapSize;

CCSize PathSearchInfo::m_tileSize;

int PathSearchInfo::m_startX;

int PathSearchInfo::m_startY;

int PathSearchInfo::m_endX;

int PathSearchInfo::m_endY;

CCScene* HelloWorld::scene()
{
 // 'scene' is an autorelease object
 CCScene *scene = CCScene::create();
 
 // 'layer' is an autorelease object
 HelloWorld *layer = HelloWorld::create();

 // add layer as a child to scene
 scene->addChild(layer);

 // return the scene
 return scene;
}

// on "init" you need to initialize your instance
void HelloWorld::onEnter()
{
 CCDirector* pDirector = CCDirector::sharedDirector();
 pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
 CCLayer::onEnter();

}

bool HelloWorld::init()
{
 //////////////////////////////
 // 1. super init first
 if ( !CCLayer::init() )
 {
 return false;
 }
 
 CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
 CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

 /////////////////////////////
 // 2. add a menu item with "X" image, which is clicked to quit the program
 // you may modify it.


 
 CCLabelTTF* pLabel = CCLabelTTF::create("A* + tiledMap", "Arial", 24);
 
 // position the label on the center of the screen
 pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
 origin.y + visibleSize.height - pLabel->getContentSize().height));

 // add the label as a child to this layer
 this->addChild(pLabel, 1);

 this->scheduleUpdate();

 CCTMXTiledMap* map = CCTMXTiledMap::create("gameMap.tmx");
 this->addChild(map);
 map->setPosition(CCPoint());
 CCTMXLayer* _road = map->layerNamed("road");//行走路径的地图
 CCSize _mapSize = map->getMapSize();
 for (int j = 0; j < _mapSize.height; j++) {
 for (int i = 0; i < _mapSize.width; i++) {
 CCSprite* _sp = _road->tileAt(CCPoint(i, j));
 if (_sp) {
 PathSprite* _pathSprite = new PathSprite(_sp);
 _pathSprite->m_x = i;
 _pathSprite->m_y = j;
 PathSearchInfo::m_inspectArray[i][j] = _pathSprite;//把地图中所有的点一一对应放入检测列表中
 }
 }
 }
 PathSearchInfo::m_mapSize = _mapSize;//获取地图的尺寸
 PathSearchInfo::m_tileSize = map->getTileSize();//获取瓦片的尺寸
 
 //设置起始和终点
 PathSearchInfo::m_startX =30;
 PathSearchInfo::m_startY = 75;

 //创建一个人物
 m_player = new PathSprite(CCSprite::create("10001.png"));
 m_player->m_sprite->setAnchorPoint(CCPoint(0.5,0));
 this->addChild(m_player->m_sprite);
 
 m_player->m_x = PathSearchInfo::m_startX;//设置人物的起始的地图坐标
 m_player->m_y = PathSearchInfo::m_startY;
 
 m_orignPoint = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY]->m_sprite->getPosition();
 m_player->m_sprite->setPosition(m_orignPoint);//设置人物的起始的世界坐标

 
 
 return true;
}
void HelloWorld::calculatePath()
{
 
 //得到开始点的节点
 PathSprite* _startNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY];
 //得到结束点的节点
 PathSprite* _endNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_endX][PathSearchInfo::m_endY];
 
 //因为是开始点 把到起始点的距离设为0, F值也为0
 _startNode->m_costToSource = 0;
 _startNode->m_FValue = 0;
 
 //把已经检测过的点从检测列表中删除
 PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY] = NULL;
 //把该点放入已经检测过点的列表中
 PathSearchInfo::m_haveInspectList.push_back(_startNode);
 //然后加入开放列表
 PathSearchInfo::m_openList.push_back(_startNode);
 
 PathSprite* _node = NULL;
 while (true)
 {
 //得到离起始点最近的点(如果是第一次执行, 得到的是起点)
 _node = PathSearchInfo::getMinPathFormOpenList();
 if (!_node)
 {
 //找不到路径
 break;
 }
 //把计算过的点从开放列表中删除
 PathSearchInfo::removeObjFromOpenList( _node);
 int _x = _node->m_x;
 int _y = _node->m_y;
 
 //
 if (_x ==PathSearchInfo::m_endX && _y == PathSearchInfo::m_endY)
 {
 break;
 }
 
 //检测8个方向的相邻节点是否可以放入开放列表中
 CCLog("%d, %d",_x, _y);
 PathSprite* _adjacent = PathSearchInfo::getObjFromInspectArray( _x + 1, _y + 1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x +1, _y);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x +1, _y-1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x , _y -1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y - 1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y+1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 _adjacent = PathSearchInfo::getObjFromInspectArray( _x , _y+1);
 PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode);
 
 }
 
 while (_node)
 {
 //把路径点加入到路径列表中
 PathSearchInfo::m_pathList.insert(PathSearchInfo::m_pathList.begin(), _node);
 _node = _node->m_parent;
 }
}


void HelloWorld::drawPath( )
{
 for (vector::iterator iter = PathSearchInfo::m_pathList.begin(); iter != PathSearchInfo::m_pathList.end(); iter++)
 {
 (*iter)->m_sprite->setColor(ccGREEN);
 }
 
}
CCRect getBoundingBox(float x, float y, float width, float height)
{
 return CCRect(x - width/2, y - height/2, width, height);
}
bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{

 //清除之前的路径
 clearPath();
 
 auto nodePosition = convertToNodeSpace( touch->getLocation() );
 CCLog("%f, %f", nodePosition.x, nodePosition.y);
// for (int i = 0; i < PathSearchInfo::m_inspectList.size(); i++)
// {
// PathSprite* _sp = PathSearchInfo::m_inspectList[i];
// 
// CCRect _rect = getBoundingBox( _sp->m_sprite->getPositionX(), _sp->m_sprite->getPositionY(), _sp->m_sprite->getContentSize().width, _sp->m_sprite->getContentSize().height);
// 
// if (_rect.containsPoint(nodePosition))
// {
 PathSprite* _sp = PathSearchInfo::m_inspectArray[(int)(nodePosition.x/PathSearchInfo::m_tileSize.width)][(int)(PathSearchInfo::m_mapSize.height - nodePosition.y/PathSearchInfo::m_tileSize.height)];
 if (_sp) {
 CCLog("%f, %f", _sp->m_sprite->getPositionX(), _sp->m_sprite->getPositionY());
 //获取触摸点, 设置为终点
 PathSearchInfo::m_endX = _sp->m_x;
 PathSearchInfo::m_endY = _sp->m_y;
 //计算路径
 calculatePath();
 //绘制路径
 drawPath( );
 //移动物体
 playerMove();
 }
 
 
// }
// 
// }

 return true;
}

void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{

}



void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{

}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
	CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
 CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
 exit(0);
#endif
#endif
}

void HelloWorld::clearPath()
{
 for (vector::iterator iter = PathSearchInfo::m_haveInspectList.begin(); iter != PathSearchInfo::m_haveInspectList.end(); iter++)
 {
 (*iter)->m_sprite->setColor(ccWHITE);
 (*iter)->m_costToSource = 0;
 (*iter)->m_FValue = 0;
 (*iter)->m_parent = NULL;
 (*iter)->m_child = NULL;
 
 PathSearchInfo::m_inspectArray[(*iter)->m_x][(*iter)->m_y] = (*iter);
 }
 
 //把移除了障碍物的地图放入检测列表中
 //PathSearchInfo::m_inspectList = PathSearchInfo::m_mapList;
 PathSearchInfo::m_openList.clear();
 PathSearchInfo::m_pathList.clear();
 PathSearchInfo::m_haveInspectList.clear();
 PathSearchInfo::m_startX = m_player->m_x;
 PathSearchInfo::m_startY = m_player->m_y;
 m_player->m_sprite->stopAllActions();
 
 m_playerMoveStep = 0;
}

void HelloWorld::playerMove()
{
 m_playerMoveStep++;
 
 if (m_playerMoveStep >= PathSearchInfo::m_pathList.size()) {
 return;
 }
 
 m_player->m_x = PathSearchInfo::m_pathList[m_playerMoveStep]->m_x;
 m_player->m_y = PathSearchInfo::m_pathList[m_playerMoveStep]->m_y;
 
 //根据路径列表移动人物
 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));
 
}
void HelloWorld::update(float dt)
{
 this->setPosition(m_orignPoint - m_player->m_sprite->getPosition());
}

文档

cocos2dxA*+tiledMap

cocos2dxA*+tiledMap:前面一章讲了cocos2dx 中使用A星算法 这章中讲 A*结合tiledmap 先看下效果图 图有点丑,忍受下 绿色的块 表示人物的行走的路线(A*算法的结果) 红色部分 表示A*算法搜寻过的点(越少,速度越快) 黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物 这张图
推荐度:
标签: 前面 讲了 coc
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top