cocos2dx-3.10 45度地图 tiledmap+A*寻路

转载请注明出处

45度地图 寻路主要参考了某位博客文章,链接如下:
cocos2dx 45度Staggered格式A*寻路 曼哈顿算法(待优化)
另外也参考了某位作者的正方形A* 寻路,所以这套A* 算法是可以兼正方形寻路也可以45度菱形寻路的。
现贴下代码:
地图类:

#ifndef _MAP_LAYER_H_
#define _MAP_LAYER_H_
#include <cocos2d.h>
#include "Role.h"
#include "Astar.h" 
#include <iostream>  
#include "common/BaseInfo.h"
#include "common/Global.h"
#include "Role.h"


USING_NS_CC;

class Role;

class MapLayer : public Layer,public BaseInfo,public Global
{
public:
    MapLayer();
    ~MapLayer();
    int _screenWidth, _screenHeight;  // 屏幕宽度和高度
    virtual bool init();
    void update(float dt);
    void setViewpointCenter(Point pos);

    void initMapWithFile(const char * path);

    static cocos2d::Scene* createScene();
    CREATE_FUNC(MapLayer);

private:
    Role *CRole; //玩家角色

};

#endif
#include "MapLayer.h"

MapLayer::MapLayer()
{
}
MapLayer::~MapLayer()
{
}

Scene* MapLayer::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = MapLayer::create();

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

    // return the scene
    return scene;
}
bool MapLayer::init()
{
    if (!Layer::init())
    {
        return false;
    }

    this->initMapWithFile("chi.tmx");//地图初始化

    astar.InitAstar(_grid, MapWidth, MapHeight);
    auto gameListener = EventListenerTouchOneByOne::create();
    // 响应触摸事件函数
    gameListener->onTouchBegan = [](Touch* touch, Event* event){return true; };
    gameListener->onTouchEnded = [=](Touch *touch, Event *event)
    {
        // OpenGL坐标
        Vec2 touchLocation = touch->getLocation();
        // 将触摸点坐标转换成相对的Node坐标
        Vec2 nodeLocation = this->convertToNodeSpace(touchLocation);

        // 用玩家位置作为起点,触摸点作为终点,转换为网格坐标,在地图上查找最佳到达路径
        Vec2 from = tileCoordForPosition(CRole->getPosition());
        Vec2 to = tileCoordForPosition(nodeLocation);
        // 如果终点是不可通过(即有障碍物)的位置,则直接return

        int tileGid = _collidable->getTileGIDAt(to);
        if (tileGid)
        {
            // 使用GID来查找指定tile的属性,返回一个Value
            Value properties = _tileMap->getPropertiesForGID(tileGid);
            // 返回的Value实际是一个ValueMap
            ValueMap map = properties.asValueMap();
            // 查找ValueMap,判断是否有”可碰撞的“物体,如果有,直接返回
            std::string value = map.at("collidable").asString();
            if (value.compare("true") == 0) 
            {
                return;
            }
        }

        CRole->path.clear();
        int fromx = (int)from.x;
        int fromy = (int)from.y;
        int tox = (int)to.x;
        int toy = (int)to.y;
        APoint start(fromx, fromy);
        APoint end(tox, toy);
        //A*算法找寻路径  
        auto t1 = ::clock();
        CRole->path = astar.GetPath(start, end, false);
        auto t2 = ::clock();
        CRole->PathCurrentStep = 1;
        CRole->PathSteps = CRole->path.size() - 1;
        CRole->bMoving = true;
        log("path size===>%d,  time=====>%d ms", CRole->path.size(),t2-t1);

        for (auto &p : CRole->path)
        {
            log("point===============>%d,%d",p->x,p->y);
        }
        if (CRole->path.size()>0)
        {
            CRole->RoleMove();
        }

    };
    // 添加场景优先事件监听器
    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(gameListener, this);

    //设置起始和结束点
    this->scheduleUpdate();

    return true;

}
void MapLayer::initMapWithFile(const char * path)
{
    _tileMap = TMXTiledMap::create(path);
    //_tileMap = cocos2d::experimental::TMXTiledMap::create(path);
    _collidable = _tileMap->getLayer("collidable");
    _collidable->setVisible(true);
    auto bg= _tileMap->getLayer("back");
    bg->setVisible(true);
    _tileMap->setPosition(Vec2(0, 0));
    MapWidth = _tileMap->getMapSize().width;
    MapHeight = _tileMap->getMapSize().height;
    this->initGrid();
    this->addChild(_tileMap);
    CRole = Role::create();
    CRole->setPosition(positionForTileCoord(Point(8,286))); 
    CRole->setSumLifeValue(200);
    CRole->setCurtLifeValue(CRole->getSumLifeValue());
    CRole->_tileMap = _tileMap;
    CRole->MapHeight = MapHeight;
    CRole->MapWidth = MapWidth;
    CRole->SetState(Role::ActionState::IDLE_STATE_UP);
    this->addChild(CRole,2);
}



void MapLayer::setViewpointCenter(Point pos)  //这个是移动地图,同时跟踪X,Y轴标准算法
{
    Size winSize = Director::getInstance()->getWinSize();
    //如果主角坐标小于屏幕的一半,则取屏幕中点坐标,否则取对象的坐标  
    int x = MAX(pos.x, winSize.width / 2);
    int y = MAX(pos.y, winSize.height / 2);

    //如果X、Y的坐标大于右上角的极限值,则取极限值的坐标(极限值是指不让地图超出屏幕造成出现黑边的极限坐标 )
    x = MIN(x, (_tileMap->getMapSize().width *_tileMap->getTileSize().width) - winSize.width / 2);
    y = MIN(y, (_tileMap->getMapSize().height * _tileMap->getTileSize().height) - winSize.height / 2);

    //对象当前所在坐标
    Point actualPosition = Vec2(x, y);

    //计算屏幕中点和所要移动的目的点之间的距离
    Point centerOfView = Vec2(winSize.width / 2, winSize.height / 2);
    Point viewPoint = centerOfView - actualPosition;
    this->setPosition(viewPoint);
}




void MapLayer::update(float delta)
{   
    this->setViewpointCenter(CRole->getPosition());
}

角色类,这里直接用了3d模型做主角:

#ifndef _ROLE_H_
#define _ROLE_H_
#include "cocos2d.h"
#include "Astar.h"
#include "common/BaseInfo.h"

USING_NS_CC;

//基础角色类,主角和NPC都需要继承它

class BaseInfo;

class Role :public Node,public BaseInfo
{
public:
    Role(void);
    ~Role(void);
    /* 角色状态设定,初始化角色状态等 */
    CC_SYNTHESIZE(std::string, name, name);                         //角色名称
    CC_SYNTHESIZE(float, curtLifevalue, CurtLifeValue);             //角色当前生命值
    CC_SYNTHESIZE(float, sumLifevalue, SumLifeValue);                   //角色总体生命值

public:
    enum class ActionState {
        ACTION_STATE_IDLE = 0,
        RUN_STATE_UP,
        RUN_STATE_DOWN,
        RUN_STATE_LEFT,
        RUN_STATE_RIGHT,
        RUN_STATE_LEFTUP,
        RUN_STATE_RIGHTUP,
        RUN_STATE_LEFTDOWN,
        RUN_STATE_RIGHTDOWN,
        IDLE_STATE_UP,
        IDLE_STATE_DOWN,
        IDLE_STATE_LEFT,
        IDLE_STATE_RIGHT,
        IDLE_STATE_LEFTUP,
        IDLE_STATE_RIGHTUP,
        IDLE_STATE_LEFTDOWN,
        IDLE_STATE_RIGHTDOWN,
    };

public:

    Action* m_down_idle;
    Action* m_right_idle;
    Action* m_up_idle;
    Action* m_left_idle;
    Action* m_leftdown_idle;
    Action* m_rightdown_idle;
    Action* m_leftup_idle;
    Action* m_rightup_idle;

    Action* m_down_walk;
    Action* m_right_walk;
    Action* m_up_walk;
    Action* m_left_walk;
    Action* m_leftdown_walk;
    Action* m_rightdown_walk;
    Action* m_leftup_walk;
    Action* m_rightup_walk;

    //角色初始化
    virtual bool init();
    //初始化创建角色动作
    void CreateActions();
    //角色移动
    //virtual void RoleMove();

    CREATE_FUNC(Role);

    void SetState(ActionState actionState);
    bool bMoving;
    unsigned int PathCurrentStep;
    unsigned int PathSteps;

    Vector<APoint *> path;
    ActionState currActionState;
    Sprite3D *_player;

    void RoleMove();



};
#endif
#include "Role.h"

Role::Role(void) :
m_down_idle(NULL),
m_up_idle(NULL),
m_left_idle(NULL),
m_right_idle(NULL),
m_leftdown_idle(NULL),
m_rightdown_idle(NULL),
m_leftup_idle(NULL),
m_rightup_idle(NULL),
m_down_walk(NULL),
m_up_walk(NULL),
m_left_walk(NULL),
m_right_walk(NULL),
m_leftdown_walk(NULL),
m_rightdown_walk(NULL),
m_leftup_walk(NULL),
m_rightup_walk(NULL),
currActionState(ActionState::ACTION_STATE_IDLE)
{
    //this->setRoleDirection(RolelTurnRight);//设定初始朝向
}
Role::~Role(void)
{

}

bool Role::init(){
    bool ret = false;
    do
    {   
        //加载模型文件
        std::string fileName = "orc.c3b";  //"orc.c3b";
        _player = Sprite3D::create(fileName);
        _player->setScale(3.0f);
        _player->setPosition(Vec2(0, 0));
        _player->setGlobalZOrder(1);
        _player->setRotation3D(Vec3(0, 180, 0));
        addChild(_player);
        //加载武器
        auto sp = Sprite3D::create("axe.c3b");
        sp->setGlobalZOrder(1);
        //将武器放到玩家手上
        _player->getAttachNode("Bip001 R Hand")->addChild(sp);
        //获取骨骼动画信息
        auto animation = Animation3D::create(fileName);
        if (animation)
        {
            auto _idle = Animate3D::create(animation);
            _idle->retain();
            //让精灵循环播放动作
            Sequence*   pSequence = Sequence::create(_idle, NULL);
            _player->runAction(RepeatForever::create(pSequence));
        }

        this->addChild(_player);

        bMoving = false;
        CreateActions();
        PathCurrentStep = 0;
        PathSteps = 0;
        ret = true;
    } while (0);

    return ret;
}

void Role::CreateActions()
{
    //初始化用户的动作


}


void Role::SetState(ActionState actionState)
{
    this->stopAllActions();
    switch (actionState)
    {
    case ActionState::IDLE_STATE_UP:    
        _player->setRotation3D(Vec3(0, 0, 0));
        break;
    case ActionState::IDLE_STATE_DOWN:
        _player->setRotation3D(Vec3(0, 180, 0));
        break;
    case ActionState::IDLE_STATE_LEFT:
        _player->setRotation3D(Vec3(0, 90, 0));
        break;
    case ActionState::IDLE_STATE_RIGHT:
        _player->setRotation3D(Vec3(0, -90, 0));
        break;
    case ActionState::IDLE_STATE_LEFTUP:
        _player->setRotation3D(Vec3(0, -135, 0));
        break;
    case ActionState::IDLE_STATE_RIGHTUP:
        _player->setRotation3D(Vec3(0, 45, 0));
        break;
    case ActionState::IDLE_STATE_LEFTDOWN:
        _player->setRotation3D(Vec3(0, -45, 0));
        break;
    case ActionState::IDLE_STATE_RIGHTDOWN:
        _player->setRotation3D(Vec3(0, 135, 0));
        break;
    case ActionState::RUN_STATE_UP:
        _player->setRotation3D(Vec3(0, 0, 0));
        break;
    case ActionState::RUN_STATE_DOWN:
        _player->setRotation3D(Vec3(0, 180, 0));
        break;
    case ActionState::RUN_STATE_LEFT:
        _player->setRotation3D(Vec3(0, 90, 0));
        break;
    case ActionState::RUN_STATE_RIGHT:
        _player->setRotation3D(Vec3(0, -90, 0));
        break;
    case ActionState::RUN_STATE_LEFTUP:
        _player->setRotation3D(Vec3(0, -135, 0));
        break;
    case ActionState::RUN_STATE_RIGHTUP:
        _player->setRotation3D(Vec3(0, -45, 0));
        break;
    case ActionState::RUN_STATE_LEFTDOWN:
        _player->setRotation3D(Vec3(0, 45, 0));
        break;
    case ActionState::RUN_STATE_RIGHTDOWN:
        _player->setRotation3D(Vec3(0, 135, 0));
        break;
    default:
        break;
    }
    currActionState = actionState;
}



void Role::RoleMove()
{
    Vector<FiniteTimeAction* > Actions;
    if (bMoving)
    {
        //角色当前所在格子坐标
        auto currpos = tileCoordForPosition(this->getPosition());
        if (currpos.x==this->path.at(PathSteps)->x && currpos.y == this->path.at(PathSteps)->y)
        {
            //已到达目的地
            this->SetState(ActionState::IDLE_STATE_UP);
        } 
        else
        {
            for (int i = 0; i < PathSteps; i++)
            {
                auto netStep = Point(this->path.at(i + 1)->x, this->path.at(i + 1)->y);
                Point v = Point(this->path.at(i)->x, this->path.at(i)->y)-netStep;
                float len = v.getLength();// 计算每一段的距离
                float duration = len / 10 * 1.2; //计算每段行走的时间
                float rad = v.getAngle(Point(1, 1));
                float Degree = CC_RADIANS_TO_DEGREES(rad);
                log("the degree=========> %f",Degree);

                auto fnSetState = [](Role *pRole, ActionState state)
                {
                    pRole->SetState(state);
                };

                if (Degree >= 0 && Degree < 45)
                {
                //  Actions.pushBack(CallFunc::create(bind(fnSetState, this, ActionState::RUN_STATE_RIGHT)));
                    SetState(ActionState::RUN_STATE_LEFT);
                }
                if (Degree >= 45 && Degree < 90)
                {
                //  Actions.pushBack(CallFunc::create(bind(fnSetState, this, ActionState::RUN_STATE_RIGHTUP)));
                    SetState(ActionState::RUN_STATE_LEFTDOWN);
                }
                if (Degree >= 90 && Degree < 135)
                {
                //  Actions.pushBack(CallFunc::create(bind(fnSetState, this, ActionState::RUN_STATE_UP)));
                    SetState(ActionState::RUN_STATE_RIGHTDOWN);
                }
                if (Degree >= 135 && Degree < 180)
                {
                //  Actions.pushBack(CallFunc::create(bind(fnSetState, this, ActionState::RUN_STATE_LEFTUP)));
                    SetState(ActionState::RUN_STATE_RIGHT);
                }
                if (Degree >-135 && Degree <= -180)
                {
                //  Actions.pushBack(CallFunc::create(bind(fnSetState, this, ActionState::RUN_STATE_LEFT)));
                    SetState(ActionState::RUN_STATE_RIGHTUP);
                }

                FiniteTimeAction *pAct = MoveTo::create(duration, positionForTileCoord(netStep));
                Actions.pushBack(pAct);



            }


            auto pSeq = Sequence::create(Actions);
            pSeq->setTag(1);
            this->runAction(pSeq);

        }
        bMoving = false;
    }
    else {
        SetState(ActionState::IDLE_STATE_DOWN);
    }

}

A* 寻路类:

#pragma once  
/*
//A*算法对象类
*/
#include <vector>  
#include <list>  
#include <unordered_map>
#include "cocos2d.h"
USING_NS_CC;
using namespace std;



//横向移动一格的路径评分
static const int COST_HORIZONTAL = 20;
//竖向移动一格的路径评分
static const int COST_VERTICAL = 5;
//斜向移动一格的路径评分
static const int COST_DIAGONAL = 12;

const int kCost1 = 10; //直移一格消耗  
const int kCost2 = 14; //斜移一格消耗  

struct APoint :public Ref
{
    int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列  
    int F, G, H; //F=G+H  
    APoint *parent; //parent的坐标,这里没有用指针,从而简化代码  
    APoint(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL)  //变量初始化  
    {
    }
};


class Astar
{
public:
    void InitAstar(std::vector<bool> &_maze,int mapwidth, int mapheight);
    Vector<APoint *> GetPath(APoint &startPoint, APoint &endPoint, bool isIgnoreCorner);

private:
    APoint *findPath(APoint &startPoint, APoint &endPoint, bool isIgnoreCorner);
    Vector<APoint *> getSurroundPoints(const APoint *point, bool isIgnoreCorner) const;
    bool isCanreach(const APoint *point, const APoint *target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断  
    APoint *isInList(const Vector<APoint *> &list, const APoint *point) const; //判断开启/关闭列表中是否包含某点  
    APoint *getLeastFpoint(); //从开启列表中返回F值最小的节点  
    //计算FGH值  
    int calcG(APoint *temp_start, APoint *point);
    int calcH(APoint *point, APoint *end);
    int calcF(APoint *point);
private:
    std::vector<bool> maze;
    Vector<APoint *> openList;  //开启列表  
    Vector<APoint *> closeList; //关闭列表  



    int width;
    int height;
};
#include <math.h>  
#include "Astar.h"  


void Astar::InitAstar(std::vector<bool> &_maze, int mapwidth, int mapheight)
{
    maze = _maze;
    width = mapwidth;
    height = mapheight;
}

int Astar::calcG(APoint *temp_start, APoint *point)
{
    /* 原正方形  */
    //int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
    //int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空  
    //return parentG + extraG;

    //45度菱形

    int g = 0;
    if (temp_start->y == point->y) // 横向  左右
    {
        g = temp_start->G + COST_HORIZONTAL;
    }
    else if (temp_start->y + 2 == point->y || temp_start->y - 2 == point->y) // 竖向  上下
    {
        g = temp_start->G + COST_VERTICAL * 2;
    }
    else // 斜向  左上 左下 右上 右下
    {
        g = temp_start->G + COST_DIAGONAL;
    }
    return g;
}

int Astar::calcH(APoint *point, APoint *end)
{
    //原正方形 用简单的欧几里得距离计算H
//  return sqrt((double)(end->x - point->x)*(double)(end->x - point->x) + (double)(end->y - point->y)*(double)(end->y - point->y))*kCost1;

    //45度菱形  曼哈顿算法
    int to0 = point->x * COST_HORIZONTAL + ((int)point->y & 1) * COST_HORIZONTAL / 2;
    int endTo0 = end->x * COST_HORIZONTAL + ((int)end->y & 1) * COST_HORIZONTAL / 2;
    return abs((float)endTo0 - (float)to0) + abs((float)end->y - (float)point->y) * COST_VERTICAL;
}

int Astar::calcF(APoint *point)
{
    return point->G + point->H;
}

APoint *Astar::getLeastFpoint()
{

    if (!openList.empty())
    {
        auto resPoint = openList.front();
        for (auto point : openList)
        if (point->F<resPoint->F)
            resPoint = point;
        return resPoint;
    }
    return NULL;
}

APoint *Astar::findPath(APoint &startPoint, APoint &endPoint, bool isIgnoreCorner)
{
    openList.clear();
    closeList.clear();
    //CCLOG("%d,%d", startPoint.x,startPoint.y);
    //CCLOG("%d,%d", endPoint.x,endPoint.y);
    openList.pushBack(new APoint(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离  
    while (!openList.empty())
    {
        auto curPoint = getLeastFpoint(); //找到F值最小的点  
        openList.eraseObject(curPoint); //从开启列表中删除  
        closeList.pushBack(curPoint); //放到关闭列表  
        //1,找到当前周围八个格中可以通过的格子  
        auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
        for (auto &target : surroundPoints)
        {
            //2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H  
            if (!isInList(openList, target))
            {
                target->parent = curPoint;

                target->G = calcG(curPoint, target);
                target->H = calcH(target, &endPoint);
                target->F = calcF(target);

                openList.pushBack(target);
            }
            //3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F  
            else
            {
                int tempG = calcG(curPoint, target);
                if (tempG<target->G)
                {
                    target->parent = curPoint;

                    target->G = tempG;
                    target->F = calcF(target);
                    //CCLOG("%d,%d", target.x, target.y);
                }
            }
            APoint *resPoint = isInList(openList, &endPoint);
            if (resPoint)
                return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝  
        }
    }

    return NULL;
}

Vector<APoint *> Astar::GetPath(APoint &startPoint, APoint &endPoint, bool isIgnoreCorner)
{
    log("from point===============>%d,%d", startPoint.x, startPoint.y);
    log("to point===============>%d,%d", endPoint.x, endPoint.y);
    APoint *result = findPath(startPoint, endPoint, isIgnoreCorner);
    Vector<APoint *> path;
    //返回路径,如果没找到路径,返回空链表  
    int s = 1;
    while (result->parent)
    {       
     // result->y = height - result->y - 1;
        path.insert(0,result);
        result = result->parent;
        s++;
    }
    log("s===>%d",s);
    return path;
}

APoint *Astar::isInList(const Vector<APoint *> &list, const APoint *point) const
{
    //判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标  
    for (auto p : list)
    if (p->x == point->x&&p->y == point->y)
        return p;
    return NULL;
}

bool Astar::isCanreach(const APoint *point, const APoint *target, bool isIgnoreCorner) const
{
    if (target->x<0 || target->x>width-1
        || target->y<0 || target->y>height-1
        || maze[width*target->y + target->x] == false
        || (target->x == point->x&&target->y == point->y)
        || isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false  
        return false;
    else
    {
        if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以  
            return true;
        else
        {
            //斜对角要判断是否绊住  
            if (maze[width*target->y + point->x] == true && maze[width*point->y + target->x] == true)
                return true;
            else
                return isIgnoreCorner;
        }
    }
}

Vector<APoint *> Astar::getSurroundPoints(const APoint *point, bool isIgnoreCorner) const
{
    Vector<APoint *> surroundPoints;

    //原正方形
    /*for (int x = point->x - 1; x <= point->x + 1; x++)
    for (int y = point->y - 1; y <= point->y + 1; y++)
    if (isCanreach(point, new APoint(x, y), isIgnoreCorner))
        surroundPoints.pushBack(new APoint(x, y));*/

    //45度菱形  菱形组合的地图八方向与正常不同

    // 左
    auto p = new APoint(point->x - 1, point->y);
    if (isCanreach(point, p, isIgnoreCorner)) // 可走并且不在关闭列表
    {
        surroundPoints.pushBack(p);
    }

    // 右
    p = new APoint(point->x + 1, point->y);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    // 上
    p = new APoint(point->x, point->y-2);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }
    // 下
    p = new APoint(point->x , point->y+2);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    // 左上
    p = new APoint(point->x - 1+ ((int)point->y & 1), point->y-1);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    // 左下
    p = new APoint(point->x - 1 + ((int)point->y & 1), point->y + 1);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    //右上
    p = new APoint(point->x  + ((int)point->y & 1), point->y - 1);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    //右下
    p = new APoint(point->x + ((int)point->y & 1), point->y +1);
    if (isCanreach(point, p, isIgnoreCorner))
    {
        surroundPoints.pushBack(p);
    }

    return surroundPoints;
}

主要代码已经贴上了:下面是本demo图片,随便做的,看看就行
这里写图片描述

本文demo代码请到如下地址下载,图片资源来自网络,切勿商用。
下载资源

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值