总结、代码、效果看Cocos2d-x 3.3TileMap的A*算法实现详解
总结:
- Cocos里面的Vector比C++的vector容纳的类型少很多,因此用标准库的vector
- 地图是320*680,瓦片是32*32像素
- 首先添加点击事件,获取终点的瓦片坐标,并记录下来
- 设定起始坐标,并将起始坐标作为【当前点】
- 每次对【当前点】的四周探索,放入优先队列openList
- 将优先队列的第一个元素,即F值最小的那个点,作为新的【当前点】,并放入closeList
- 继续调用探索方法,直到终点坐标也被放入openList
代码:
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include “cocos2d.h”#include <queue>#include <vector>USING_NS_CC;//定义【当前点】类,包含权值F和坐标点classpointValue{public:pointValue(Point tem, Point dst , inttotal){tempPoint = tem;FValue = (abs((int)dst.x-(int)tem.x +(int)dst.y-(int)tem.y) + total) ;}//当前点坐标,和F值Point tempPoint;intFValue;};//设置优先队列比较函数,F值最小的【当前点】在优先队列的TopstructCompare{booloperator ()(pointValue a,pointValue b){returna.FValue > b.FValue;}};classHelloWorld : publiccocos2d:ayer{public:staticcocos2d::Scene* createScene();virtualboolinit();CREATE_FUNC(HelloWorld);voidmenuCloseCallback(cocos2d::Ref* pSender);//二维数组,防止点重复探索,初始化为0,探索过的设为1intarr[15][10];//TileMap的层TMXLayer *layer;//待检测坐标列表,优先队列作为OpenListstd::priority_queue<pointValue, std::vector<pointValue>,Compare> p_quene;//关闭列表std::vector<pointValue> closeList;std::vector<pointValue>::iterator closeListStart;//起点瓦片坐标Point beginPoint;//终点瓦片坐标Point destination;//估算一个从起始点到终点的格子数目,每移动一次,则减30inttotal;//将最终的路径所有点,存放在closeList中boolaStart();};#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include “HelloWorldScene.h”
USING_NS_CC;
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
returnscene;
}
boolHelloWorld::init()
{
if( !Layer::init() )
{
returnfalse;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//载入TileMap地图
auto map = TMXTiledMap::create(“map.tmx”);
addChild(map);
//获取TileMap的层
layer = map->getLayer(“layer1″);
//确定起点瓦片坐标和初始化二维数组
beginPoint = Point(0,0);
arr[0][0] = 1;
//点击事件监听,记录终点瓦片坐标
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [this](Touch *t, Event *e)
{
//设置终点瓦片坐标
intdx = (int)(t->getLocation().x)/32;
intdy = 14 – (int)(t->getLocation().y)/32;
this->destination = Point(dx,dy);
CCLOG(“%d,%d”,dx,dy);
//自己设置起点到终点的最短格子数估值,即G值
total = 1000;
//寻找最短路径,坐标存放在closeList里面
aStart();
returntrue;
};
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);
returntrue;
}
boolHelloWorld::aStart()
{
//每调用一次aStart相当于移动一步,每移动一步total减30,作为G值
total = total – 30;
if((int)beginPoint.x == (int)destination.x && (int)beginPoint.y == (int)destination.y)
{
returntrue;
}
//探索这个点的4周(上,右,下,左),若存在,则放进优先队列openList中
//判断上方
if((int)beginPoint.x >= 0 && ((int)beginPoint.y-1) >= 0 && (int)beginPoint.x <= 9 && ((int)beginPoint.y-1) <= 14 ){
Sprite *testUp = layer->getTileAt(Vec2((int)beginPoint.x,(int)beginPoint.y-1));
if(testUp != NULL && (arr[(int)beginPoint.x][(int)beginPoint.y-1] != 1) )
{
CCLOG(“up”);
//初始化探索的点,将它放进优先队列openList中,并设置二维数组中的值为1,防止重复探索
auto temp = newpointValue(Point(beginPoint.x,beginPoint.y-1),destination,total);
p_quene.push(*temp);
arr[(int)beginPoint.x][(int)beginPoint.y-1] = 1;
}
}
//判断左方
if(((int)beginPoint.x-1) >= 0 && (int)beginPoint.y >= 0 && ((int)beginPoint.x-1) <= 9 && (int)beginPoint.y <= 14) {
Sprite *testLeft = layer->getTileAt(Vec2((int)beginPoint.x-1,(int)beginPoint.y));
if(testLeft != NULL && (arr[(int)beginPoint.x-1][(int)beginPoint.y] != 1) )
{
CCLOG(“left”);
//初始化探索的点,将它放进优先队列openList中,并设置二维数组中的值为1,防止重复探索
auto temp2 = newpointValue(Point(beginPoint.x-1,beginPoint.y),destination,total);
p_quene.push(*temp2);
arr[(int)beginPoint.x-1][(int)beginPoint.y] = 1;
}
}
//判断下方
if((int)beginPoint.x >= 0 && ((int)beginPoint.y+1) >= 0 && (int)beginPoint.x <= 9 && ((int)beginPoint.y+1) <= 14) {
Sprite *testDown = layer->getTileAt(Vec2((int)beginPoint.x,(int)beginPoint.y+1));
if(testDown != NULL && (arr[(int)beginPoint.x][(int)beginPoint.y+1] != 1) )
{
CCLOG(“down”);
//初始化探索的点,将它放进优先队列openList中,并设置二维数组中的值为1,防止重复探索
auto temp3 = newpointValue(Point(beginPoint.x,beginPoint.y+1),destination,total);
p_quene.push(*temp3);
arr[(int)beginPoint.x][(int)beginPoint.y+1] = 1;
}
}
//判断右方
if(((int)beginPoint.x+1) >= 0 && (int)beginPoint.y >= 0 && ((int)beginPoint.x+1) <= 9 && (int)beginPoint.y <= 14){
Sprite *testRight = layer->getTileAt(Vec2((int)beginPoint.x+1,(int)beginPoint.y));
if(testRight != NULL && (arr[(int)beginPoint.x+1][(int)beginPoint.y] != 1))
{
CCLOG(“right”);
//初始化探索的点,将它放进优先队列openList中,并设置二维数组中的值为1,防止重复探索
auto temp4 = newpointValue(Point(beginPoint.x+1,beginPoint.y),destination,total);
p_quene.push(*temp4);
arr[(int)beginPoint.x+1][(int)beginPoint.y] = 1;
}
}
//重置当前位置
beginPoint.x = p_quene.top().tempPoint.x;
beginPoint.y = p_quene.top().tempPoint.y;
CCLOG(“%d,%d”,(int)beginPoint.x,(int)beginPoint.y);
//把F值最小的点,放进closeList中,并从优先队列中pop掉
closeList.push_back(p_quene.top());
p_quene.pop();
//在路径中添加精灵
auto star = Sprite::create(“star.png”);
star->setPosition(Point(beginPoint.x*32+10,480-beginPoint.y*32-10));
addChild(star);
//继续递归
aStart();
}
voidHelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox(“You pressed the close button. Windows Store Apps do not implement a close button.”,”Alert”);
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
效果: