cocos2d-x c++之A *算法(A星算法)

自以为对于cocos2d了如指掌中,但从刚买的书中了解到了A星算法;

虽然书中只是一笔带过,连代码也没有但是经过我一个月的推敲,终于完成了A星算法。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190508081411802.png?x-oss-process=image/waterm在这里插入图片描述

深灰色是搜索的路径,深绿色是最小路径。 绿色是起点,红色是终点。

A星算法,很简单。 大部分是这么解释的。

  1. 建立open集合,和close集合
  2. 把起点放进close集合中
  3. 然后把起点外层的方块位置放进open集合中
  4. 然后计算open集合 中的F值。 F=G+H。 G值是到起点的距离,h值是到终点的预估位置。(曼哈顿算法) h=|x1-x2|+|y1-y2|
  5. 找到最小的F值,然后放进close里。 也就是上图的灰色方块。
  6. 直到终点方块在close集合里。
  7. 然后根据每个方块的父节点,逆推到起点。

最开始,就是一个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);
        }
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昏暗的夜晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值