如何实现A星寻路算法 Cocos2d-x 3 0 beta2

本文介绍了如何在Cocos2D-x 3.0中实现A星寻路算法,通过创建ShortestPathStep类、Open和Closed列表,实现猫在地图上避开障碍物的路径规划。详细步骤包括设置游戏场景、计算路径、跟随路径前进以及重新添加游戏逻辑,确保猫能流畅移动并解决游戏中的问题。
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

       本文实践自 Johann Fradj 的文章《How To Implement A* Pathfinding with Cocos2D Tutorial》,文中使用Cocos2D,我在这里使用Cocos2D-x 3.0进行学习和移植。在这篇文章,将会学习到如何在Cocos2D中实现A星算法。在开始之前,先阅读文章《Introduction to A* Pathfinding》将会有所帮助。

步骤如下:
1.下载本文章的准备工程,编译运行,如下图所示:

在这款游戏中,猫需要通过由狗守卫的地牢,除非拿骨头贿赂狗,不然狗会将猫吃掉。注意到猫只能水平或垂直的移动,每次只能移动一个方块。

2.开始修改成A星寻路算法。打开CatSprite.h文件,创建ShortestPathStep内部类,代表路径上的一步操作。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ShortestPathStep :  public cocos2d::Object
{
public:
    ShortestPathStep();
    ~ShortestPathStep();

     static ShortestPathStep *createWithPosition( const cocos2d::Point &pos);
     bool initWithPosition( const cocos2d::Point &pos);

     int getFScore()  const;
     bool isEqual( const ShortestPathStep *other)  const;
    std::string getDescription()  const;

    CC_SYNTHESIZE(cocos2d::Point, _position, Position);
    CC_SYNTHESIZE( int, _gScore, GScore);
    CC_SYNTHESIZE( int, _hScore, HScore);
    CC_SYNTHESIZE(ShortestPathStep*, _parent, Parent);
};

正如所见,这是一个很简单的类,记录了以下内容:

  • 方块的坐标

  • G值(记住,这是开始点到当前点的方块数量)

  • H值(记住,这是当前点到目标点的方块估算数量)

  • Parent是它的上一步操作

  • F值,这是方块的和值(它是G+H的值)

打开CatSprite.cpp文件,添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
CatSprite::ShortestPathStep::ShortestPathStep() :
    _position(Point::ZERO),
    _gScore( 0),
    _hScore( 0),
    _parent(nullptr)
{
}

CatSprite::ShortestPathStep::~ShortestPathStep()
{
}

CatSprite::ShortestPathStep *CatSprite::ShortestPathStep::createWithPosition( const Point &pos)
{
    ShortestPathStep *pRet =  new ShortestPathStep();
     if (pRet && pRet->initWithPosition(pos))
    {
        pRet->autorelease();
         return pRet;
    }
     else
    {
        CC_SAFE_DELETE(pRet);
         return nullptr;
    }
}

bool CatSprite::ShortestPathStep::initWithPosition( const Point &pos)
{
     bool bRet =  false;
     do
    {
         this->setPosition(pos);

        bRet =  true;
    }  while ( 0);

     return bRet;
}

int CatSprite::ShortestPathStep::getFScore()  const
{
     return  this->getGScore() +  this->getHScore();
}

bool CatSprite::ShortestPathStep::isEqual( const CatSprite::ShortestPathStep *other)  const
{
     return  this->getPosition() == other->getPosition();
}

std::string CatSprite::ShortestPathStep::getDescription()  const
{
     return StringUtils::format( "pos=[%.0f;%.0f]  g=%d  h=%d  f=%d",
                                this->getPosition().x,  this->getPosition().y,
                                this->getGScore(),  this->getHScore(),  this->getFScore());
}

这里定义了getDescription方法,以方便调试。创建了isEquals方法,当且仅当两个ShortestPathSteps的方块坐标相同时,它们相等(例如它们代表着相同的方块)。

3.创建Open和Closed列表。打开CatSprite.h文件,添加如下代码:

1
2
cocos2d::Vector<ShortestPathStep*> _spOpenSteps;
cocos2d::Vector<ShortestPathStep*> _spClosedSteps;

4.检查开始和结束点。重新实现moveToward方法,获取当前方块坐标和目标方块坐标,然后检查是否需要计算一条路径,最后测试目标方块坐标是否可行走的(在这里只有墙壁是不可行走的)。打开CatSprite.cpp文件,修改moveToward方法,为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void CatSprite::moveToward( const Point &target)
{
    Point fromTileCoord = _layer->tileCoordForPosition( this->getPosition());
    Point toTileCoord = _layer->tileCoordForPosition(target);

     if (fromTileCoord == toTileCoord)
    {
        CCLOG( "You're already there! :P");
         return;
    }

     if (!_layer->isValidTileCoord(toTileCoord) || _layer->isWallAtTileCoord(toTileCoord))
    {
        SimpleAudioEngine::getInstance()->playEffect( "hitWall.wav");
         return;
    }

    CCLOG( "From: %f, %f", fromTileCoord.x, fromTileCoord.y);
    CCLOG( "To: %f, %f", toTileCoord.x, toTileCoord.y);
}

编译运行,在地图上进行点击,如果不是点击到墙壁的话,可以在控制台看到如下信息:

1
2
From: 24.000000, 0.000000
To: 22.000000, 3.000000

其中"From"就是猫的方块坐标,"To"就是所点击的方块坐标。

5.实现A星算法。根据算法,第一步是添加当前坐标到open列表。还需要三个辅助方法:

  • 一个方法用来插入一个ShortestPathStep对象到适当的位置(有序的F值)

  • 一个方法用来计算从一个方块到相邻方块的移动数值

  • 一个方法是根据"曼哈顿距离"算法,计算方块的H值

打开CatSprite.cpp文件,添加如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void CatSprite::insertInOpenSteps(CatSprite::ShortestPathStep *step)
{
     int stepFScore = step->getFScore();
    ssize_t count = _spOpenSteps.size();
    ssize_t i =  0;
     for (; i < count; ++i)
    {
         if (stepFScore <= _spOpenSteps.at(i)->getFScore())
        {
             break;
        }
    }
    _spOpenSteps.insert(i, step);
}

int CatSprite::computeHScoreFromCoordToCoord( const Point &fromCoord,  const Point &toCoord)
{
     // 这里使用曼哈顿方法,计算从当前步骤到达目标步骤,在水平和垂直方向总的步数
     // 忽略了可能在路上的各种障碍
     return abs(toCoord.x - fromCoord.x) + abs(toCoord.y - fromCoord.y);
}

int CatSprite::costToMoveFromStepToAdjacentStep( const ShortestPathStep *fromStep,  const ShortestPathStep *toStep)
{
     // 因为不能斜着走,而且由于地形就是可行走和不可行走的成本都是一样的
     // 如果能够对角移动,或者有沼泽、山丘等等,那么它必须是不同的
     return  1;
}

接下来,需要一个方法去获取给定方块的所有相邻可行走方块。因为在这个游戏中,HelloWorld管理着地图,所以在那里添加方法。打开HelloWorldScene.cpp文件,添加如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
PointArray *HelloWorld::walkableAdjacentTilesCoordForTileCoord( const Point &tileCoord)  const
{
    PointArray *tmp = PointArray::create( 4);

     // 上
    Point p(tileCoord.x, tileCoord.y -  1);
     if ( this->isValidTileCoord(p) && ! this->isWallAtTileCoord(p))
    {
        tmp->addControlPoint(p);
    }

     // 左
    p.setPoint(tileCoord.x -  1, tileCoord.y);
     if ( this->isValidTileCoord(p) && ! this->isWallAtTileCoord(p))
    {
        tmp->addControlPoint(p);
    }

     // 下
    p.setPoint(tileCoord.x, tileCoord.y +  1);
     if ( this->isValidTileCoord(p) && ! this->isWallAtTileCoord(p))
    {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值