自以为对于cocos2d了如指掌中,但从刚买的书中了解到了A星算法;
虽然书中只是一笔带过,连代码也没有但是经过我一个月的推敲,终于完成了A星算法。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190508081411802.png?x-oss-process=image/waterm
深灰色是搜索的路径,深绿色是最小路径。 绿色是起点,红色是终点。
A星算法,很简单。 大部分是这么解释的。
- 建立open集合,和close集合
- 把起点放进close集合中
- 然后把起点外层的方块位置放进open集合中
- 然后计算open集合 中的F值。 F=G+H。 G值是到起点的距离,h值是到终点的预估位置。(曼哈顿算法) h=|x1-x2|+|y1-y2|
- 找到最小的F值,然后放进close里。 也就是上图的灰色方块。
- 直到终点方块在close集合里。
- 然后根据每个方块的父节点,逆推到起点。
最开始,就是一个Titled 里的瓦片。无从下手。
最大的问题是如何定位,受到书中误导 给 每一个瓦片 按照0 到 200之间 定位。 然后想了想,这个很麻烦。
因为上下左右 问题 需要 +20,-20,+1,-1. 定位很麻烦。
所以用瓦片的代码,把每一个瓦片坐标化。 然后创建一个实体。把坐标放进实体中 ,再创建精灵 sprite->setUserObject(bean); 把实体保存在精灵中。然后创建的瓦片就是一个精灵了。 然后可以用sprite->setTag();对于精灵进行障碍物,或者起点,终点的标记。
void MapLayer::setSprite(std::string str,Vec2 vec,Vec2 vec1){
// CCLOG("aaaaaa %s",&str);
Sprite *sprite=Sprite::create(str);
sprite->setAnchorPoint(Vec2(0.0, 0.0));
sprite->setPosition(vec);
//实体bean
Bean *bean=Bean::createBean(vec1);
sprite->setUserObject(bean);
//起点
if(str=="fangkuai.png"){
sprite->setTag(3);
CCLOG("起点 x=%f, y=%f",vec1.x,vec1.y);
vec_start=Vec2(vec1.x,vec1.y);
}
//终点
if(str=="fangkuai3.png"){
sprite->setTag(2);
}
//障碍物
if(str=="fangkuan1.png"){
sprite->setTag(1);
}
this->addChild(sprite,1);
}
把起点放进close集合中,别忘了父指针。
最坑我的是我最开始以为搜索可以直达终点的。 后来发现需要一个父指针。 那么父指针式什么?就是生成方块的上一个方块。 也就是close里边的方块。 所以我在每生成方块我就把父方块的位置,保留,然后放进 子方块bean里的单独的father位置中。。
for(int i=0;i<vector_close.size();i++){
Sprite *sprite0=(Sprite*)vector_close.at(i);
Bean *bean=(Bean *)sprite0->getUserObject();
Vec2 vec=bean->getVec2();
if(vec.x+1<20&&vec.x-1>=0){
if(vec.y+1<10 && vec.y-1>=0){
Sprite *sprite1=getSrptie1(Vec2(vec.x-1,vec.y));
setOpenVector(sprite1,vec);
Sprite *sprite=getSrptie1(Vec2(vec.x+1,vec.y));
setOpenVector(sprite,vec);
Sprite *sprite2=getSrptie1(Vec2(vec.x,vec.y-1));
setOpenVector(sprite2,vec);
Sprite *sprite3=getSrptie1(Vec2(vec.x,vec.y+1));
setOpenVector(sprite3,vec);
}
}
}
void MapLayer::setOpenVector(Sprite *sprite,Vec2 vec){
if(sprite->getTag()!=1){
Bean *bean1=(Bean *)sprite->getUserObject();
//保存在父位置。
bean1->setVec2Father(vec);
vector_open.pushBack(sprite);
vectorFather1.replace(0,sprite);
aboolean1=false;
//--------------求出G值
int a=setFather();
CCLOG("G值。。。。。。。。。。%d",a);
bean1->setGN(a);
}
}
求出G值。 h值很好找,只需要曼哈顿算法。 而G值。。。。。
G值最开始我用曼哈顿算法。最开始我觉得没问题,但是遇到阻挡的时候并不能走最佳的值。
后来想了想,其实只需要用最后逆推到起点的方法就可以了。 利用每个瓦片的父位置。做一个遍历。直到逆推到起点。
int MapLayer::setFather(){
int a=0;
while (!aboolean1) {
Sprite *sprite0=vectorFather1.at(0);
Bean *bean=(Bean *)sprite0->getUserObject();
Vec2 vecf=bean->getVec2Father();
if(vec_start.equals(bean->getVec2())){
aboolean1=true;
}else{
for(int i=0;i<vector_close.size();i++){
Sprite *sprite1=vector_close.at(i);
Bean *bean1=(Bean *)sprite1->getUserObject();
if(vecf.equals(bean1->getVec2())){
vectorFather1.replace(0,sprite1);
}
}
a++;
}
}
return a;
};
寻找open集合中F的最小值。
随便创建一个集合,然后把F值得出,然后找到最小的F值。
std::vector<int> a;
for(int i=0;i<vector_open.size();i++){
Sprite *sprite=(Sprite*)vector_open.at(i);
Bean *bean=(Bean *)sprite->getUserObject();
Vec2 vec=bean->getVec2();
int H=abs(13-vec.x)+abs(4-vec.y);
int G=bean->getGN();
int F=H+G;
a.push_back(F);
}
//f里边最小值
int minF=findmin(a);
最小值方法很简单。
int MapLayer::findmin(std::vector<int> vec){
int min=999;
for(int v:vec){
if(v<min){
min=v;
}
}
return min;
};
从open集合中找到刚才求到的最小值。
for(int i=0;i<vector_open.size();i++){
Sprite *sprite=(Sprite*)vector_open.at(i);
Bean *bean=(Bean *)sprite->getUserObject();
Vec2 vec=bean->getVec2();
int H=abs(13-vec.x)+abs(4-vec.y);
int G=bean->getGN();
int F=H+G;
if(minF==F){
log("坐标 F =%d ",F);
log("坐标 G =%d ",G);
log("坐标 H =%d ",H);
//打上不能在放进open中的标记。避免重复放进close中。
sprite->setTag(1);
CCLOG("Gn=%d",bean->getGN());
vector_close.pushBack(sprite);
vector_open.clear();
}
}
把close 里的sprite值附上颜色 就是深灰色。 当搜索范围完成以后,就关闭定时器。 然后开始 逆推到起点的定时器。
for(int i=0;i<vector_close.size();i++){
if(i==0){
CCLOG("——————————————————————————————————————————");
}
Sprite *sprite=(Sprite*)vector_close.at(i);
Bean *bean=(Bean *)sprite->getUserObject();
Vec2 vec=bean->getVec2();
Vec2 vef=bean->getVec2Father();
sprite->setColor((Color3B(150, 140, 130)));
// CCLOG("%d 方块x=%d,方块y=%f \t",i,vec.x,vec.y);
// int H=abs(13-vec.x)+abs(4-vec.y);
// int G=bean->getGN();
// int F=G+H;
if(vec.equals(Vec2(13, 4))){
vectorFather.clear();
vectorFather.pushBack(sprite);
CCLOG("——————————————————————————————————");
for(int i=0;i<vector_close.size();i++){
Sprite *sprite=(Sprite*)vector_close.at(i);
Bean *bean1=(Bean *)sprite->getUserObject();
Vec2 vec=bean1->getVec2();
int GN1=bean1->getGN();
int F1=bean1->getF();
CCLOG("%d 方块x=%f,方块y=%f G=%d F=%d \t",i,vec.x,vec.y,GN1,F1);
}
CCLOG("——————————————————————————————————");
schedule(schedule_selector(MapLayer::fatherbock),0.01);
unschedule(schedule_selector(MapLayer::move));
}
if(i==vector_close.size()-1){
CCLOG("——————————————————————————————————————————");
}
}
直到父位置是起点 关闭定时器
void MapLayer::fatherbock(float dt){
CCLOG("log。。。。。。。。");
Sprite *sprite=vectorFather.at(0);
Bean *bean=(Bean *)sprite->getUserObject();
if(vec_start.equals(bean->getVec2())){
//关闭定时器
unschedule(schedule_selector(MapLayer::fatherbock));
}
Vec2 vecf=bean->getVec2Father();
for(int i=0;i<vector_close.size();i++){
Sprite *sprite1=vector_close.at(i);
Bean *bean1=(Bean *)sprite1->getUserObject();
//如果父方块的位置在close中把它染成深绿色。
if(vecf.equals(bean1->getVec2())){
sprite1->setColor(Color3B(10, 100, 50));
vectorFather.replace(0,sprite1);
}
}
}