Cocos2d-x 3.1.1 学习日志16--A星算法(A*搜寻算法)的学习

A *搜寻算法俗称A星算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。常用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上。

首先:1、在Map地图中任取2个点,开始点和结束点

2、首先判断该点是不是不可以穿越的点,或者是已经再close中了

3、如果2步骤为真,什么都不做,如果为假,那么我们就进行添加了

4、如果在添加的时候,发现该点在open中不存在,那么我们直接添加,而且视之为当前节点,如果该点              存在open中,那么我们比较G值,如果发现当前节点到该节点的G小于原来的G,那么再重新设置G,F值,
             然后设置这个节点为当前节点。

5、再添判断玩之后,再添加它的4个邻接点,循环1-4的步骤。直至找到,或者说是open中为null了的时              候,就结束查询了。

代码如下:

#include <iostream>
 #include <string>
#include "AStartMap.h"
using namespace std;

int main() {
    AstartMap *gameMap = new AstartMap;
    gameMap->initMap();
    if(gameMap != 0) {
        delete gameMap;
        gameMap = 0;
    }
    return 0;
}

#ifndef ASTARTNODE_H_
#define ASTARTNODE_H_

class AStartNode
{
public:
    AStartNode();
    ~AStartNode();

public:
    void setPos(int icol, int irow);
    void setG(int iG);
    int getG();
    void setH(int iH);
    int getH();
    void setF(int iF);
    void setFID(int iFID);
    int getFID();
    int getF();
    int getCol();
    int getRow();

private:
    int m_Col;
    int m_Row;
    int m_G;
    int m_H;
    int m_F;
    int m_FID;
};// end of AStartNode

#endif // end of ASTARTNODE_H_

#include "AStartNode.h"

AStartNode::AStartNode() : m_Col(0), //
                                        m_Row(0),
                                        m_G(0),
                                        m_H(0),
                                        m_F(0),
                                        m_FID(0)
{

}

AStartNode::~AStartNode() {

}

void AStartNode::setPos(int icol, int irow) {
    m_Col = icol;
    m_Row = irow;
}

void AStartNode::setG(int iG) {
    m_G = iG;
}

int AStartNode::getG() {
    return m_G;
}

void AStartNode::setH(int iH) {
    m_H = iH;
}

int AStartNode::getH() {
    return m_H;
}

void AStartNode::setF(int iF) {
    m_F = iF;
}

int AStartNode::getF() {
    return m_F;
}

int AStartNode::getCol() {
    return m_Col;
}

int AStartNode::getRow() {
    return m_Row;
}

void AStartNode::setFID(int iFID) {
    m_FID = iFID;
}

int AStartNode::getFID() {
    return m_FID;
}

#ifndef ASTARTMAP_H_
#define ASTARTMAP_H_

#include <vector>
class AStartNode;
class AstartMap
{
public:
    typedef enum {
        STARTMAP_COL = 10,
        STARTMAP_ROW = 10,
    } StartMap;

    typedef enum {
        MAPPATH_BEGINPOINT = -2,
        MAPPATH_WALL = -1,
        MAPPATH_ROAD = 0,
        MAPPATH_ENDPOINT = 2,
    } MapPath;

    typedef enum {
        STARTNODE_G = 10,
        STARTNODE_H = 10,
    }StartNodeInfo;

public:
    AstartMap();
    ~AstartMap();

public:
    void initMap();

private:
    void _initMapBoard();
    void _initSelectBeginPoint();
    void _addIntoCloseNode(AStartNode *newCloseNode);
    void _addIntoOpenNode(AStartNode *newOpenNode);
    void _deleteBeginNodefromOpenNode(AStartNode *newOpenNode);
    void _add_adjacentnodeToOpenNode(AStartNode *newOpenNode);
    void _beginToMove();
    void _setStartNode_G_H_Value(AStartNode *newOpenNode, AStartNode *parentNode);
    bool _isWater(AStartNode *pStartNode);
	bool _isInClose(AStartNode *pStartNode);
    bool _isInOpen(AStartNode *pStartNode);

private:
    AStartNode *_getMinFstartNode();
    AStartNode *_getAStartNodeAt(int iCol, int iRow);
    void _heapRebuild(std::vector<AStartNode *> &rStartNodeArray,int root,int size);
    void _heapSort(std::vector<AStartNode *> &rStartNodeArray ,int size);

private:
    std::vector<AStartNode *> m_AstartNode;
    std::vector<AStartNode *> m_openNode;
    std::vector<AStartNode *> m_closeNode;
    AStartNode *m_pEndNode;
    int GameMap[STARTMAP_COL][STARTMAP_ROW]; // map

};// end of AstartMap

bool isNum(int inum);

#endif // end of ASTARTMAP_H_

#include "AStartNode.h"

#include <iostream>
#include <ctype.h>
#include <assert.h>
#include <cmath>

#include "AStartMap.h"

extern bool isNum(int inum);

AstartMap::AstartMap() : m_pEndNode(0)
{

}

AstartMap::~AstartMap() {

}

void AstartMap::initMap() {
    /*
    *@init the game map
    */
    _initMapBoard();
}

void AstartMap::_initMapBoard() {
    //memset(GameMap, MAPPATH_ROAD, STARTMAP_COL * STARTMAP_ROW * sizeof(int));
    for(int i = 0; i < STARTMAP_COL; ++i) {
        for(int j = 0; j < STARTMAP_ROW; ++j) {
            GameMap[i][j] = MAPPATH_ROAD;
            AStartNode *aStartNode = new AStartNode;
            aStartNode->setPos(i, j);
            m_AstartNode.push_back(aStartNode);
        }
    }

    for(int i = 0; i < 7; ++i) { // set the game wall
        GameMap[i + 2][4] = MAPPATH_WALL;
    }

    _initSelectBeginPoint();
}

void AstartMap::_initSelectBeginPoint() {
    int ibegin_xpos = 0;
    int ibegin_ypos = 0;

    std::cout<<"Select the Begin Point(X in(0-9), y in (0- 9): \n";
    std::cin>>ibegin_xpos;
    std::cin>>ibegin_ypos;
    if(!isNum(ibegin_xpos) || !isNum(ibegin_ypos))   return;

    std::cout<<"Select the End Point(X in(0-9), y in (0- 9): \n";
    int iend_xpos = 0;
    int iend_ypos = 0;
    std::cin>>iend_xpos;
    std::cin>>iend_ypos;
    if(!isNum(iend_xpos) || !isNum(iend_ypos))   return;
    GameMap[iend_xpos][iend_ypos] = MAPPATH_ENDPOINT; // set end point

    AStartNode *pBeginNode = _getAStartNodeAt(ibegin_xpos, ibegin_ypos);
    m_pEndNode = _getAStartNodeAt(iend_xpos, iend_ypos);

    if(pBeginNode == 0) return;
    pBeginNode->setG(0);
    pBeginNode->setF(0);
    pBeginNode->setH(0);
    m_openNode.push_back(pBeginNode);

    /*
    *@Game Begin
    *the player begins to move
    */
    _beginToMove();
}

void AstartMap::_beginToMove() {
    while(true) {
        AStartNode *pBeginNode = _getMinFstartNode();
        std::cout<<"select point: "<<pBeginNode->getCol()<<", "<<pBeginNode->getRow()<<std::endl;
        _add_adjacentnodeToOpenNode(pBeginNode);
        _addIntoCloseNode(pBeginNode);
        _deleteBeginNodefromOpenNode(pBeginNode);

        if(pBeginNode == m_pEndNode) { // find the end position
            std::cout<<"fine the end position"<<std::endl<<std::endl;
            break;
        }
    }
}

AStartNode *AstartMap::_getAStartNodeAt(int iCol, int iRow) {
    int iNode_Count = m_AstartNode.size();
    for(int i = 0; i < iNode_Count; ++i) {
        if(m_AstartNode[i]->getCol() == iCol && m_AstartNode[i]->getRow() == iRow) return m_AstartNode[i];
    }
    return 0;
}

void AstartMap::_addIntoCloseNode(AStartNode *newCloseNode) {
    if(newCloseNode == 0) return;
    m_closeNode.push_back(newCloseNode);
}

void AstartMap::_addIntoOpenNode(AStartNode *newOpenNode) {
    if(newOpenNode == 0) return;
    m_openNode.push_back(newOpenNode); // then other 4 node
}

void AstartMap::_add_adjacentnodeToOpenNode(AStartNode *newOpenNode) {
    int ileftNodeRow = newOpenNode->getRow() - 1;
    if(ileftNodeRow >= 0) {
        AStartNode *leftNode = _getAStartNodeAt(newOpenNode->getCol(), ileftNodeRow);

        if(!_isWater(leftNode) && !_isInClose(leftNode) ) {
            if(! _isInOpen(leftNode) ) {
                // in open
                leftNode->setFID(newOpenNode->getFID());
                _addIntoOpenNode(leftNode);
                _setStartNode_G_H_Value(leftNode, newOpenNode);
            } else {
                // not in open
               // _setStartNode_G_H_Value(leftNode, newOpenNode);
            }
        }
    }

    int irightNodeRow = newOpenNode->getRow() + 1;
    if(irightNodeRow < STARTMAP_ROW) {
        AStartNode *rightNode = _getAStartNodeAt(newOpenNode->getCol(), irightNodeRow);
        if(!_isWater(rightNode) && !_isInClose(rightNode)) {
            if(! _isInOpen(rightNode) ) {
                // in open
                rightNode->setFID(newOpenNode->getFID());
                _addIntoOpenNode(rightNode);
                 _setStartNode_G_H_Value(rightNode, newOpenNode);
            } else {
                // not in open
                //_setStartNode_G_H_Value(rightNode, newOpenNode);
            }
        }
    }

    int iupNodeCol = newOpenNode->getCol() - 1;
    if(iupNodeCol >= 0) {
        AStartNode *upNode = _getAStartNodeAt(iupNodeCol, newOpenNode->getRow());
        if(!_isWater(upNode) && !_isInClose(upNode)) {
            if( ! _isInOpen(upNode)) {
                //in open
                upNode->setFID(newOpenNode->getFID());
                _addIntoOpenNode(upNode);
                _setStartNode_G_H_Value(upNode, newOpenNode);
            } else {
                //_setStartNode_G_H_Value(upNode, newOpenNode);
            }
        }
    }

    int idownNodeCol = newOpenNode->getCol() + 1;
    if(idownNodeCol < STARTMAP_COL) {
        AStartNode *downNode = _getAStartNodeAt(idownNodeCol, newOpenNode->getRow());
        if(!_isWater(downNode) && !_isInClose(downNode)) {
            if( ! _isInOpen(downNode)) {
                //in open
                downNode->setFID(newOpenNode->getFID());
                _addIntoOpenNode(downNode);
                _setStartNode_G_H_Value(downNode, newOpenNode);
            } else {
                //_setStartNode_G_H_Value(downNode, newOpenNode);
            }
        }
    }
}

bool AstartMap::_isWater(AStartNode *pStartNode) {

    int icol = pStartNode->getCol();
    int irow = pStartNode->getRow();
    if(GameMap[icol][irow] == MAPPATH_WALL) return true;
    return false;
}

bool AstartMap::_isInClose(AStartNode *pStartNode) {
    assert(pStartNode);
    std::vector<AStartNode *>::iterator it = m_closeNode.begin();
    for( ; it != m_closeNode.end(); ++it) {
        if(*it == pStartNode) {
            return true;
        }
    }
    return false;
}

bool AstartMap::_isInOpen(AStartNode *pStartNode) {
    assert(pStartNode);
    std::vector<AStartNode *>::iterator it = m_openNode.begin();
    for(; it != m_openNode.end(); ++it) {
        if(*it == pStartNode) {
            return true;
        }
    }
    return false;
}

void AstartMap::_deleteBeginNodefromOpenNode(AStartNode *newOpenNode) {
    if(newOpenNode == 0) return;
    std::vector<AStartNode *>::iterator it = m_openNode.begin();
    for( ; it != m_openNode.end(); ++it) {
        if(*it == newOpenNode) {
            m_openNode.erase(it);
            break;
        }
    }
}

void AstartMap::_setStartNode_G_H_Value(AStartNode *newOpenNode, AStartNode *parentNode) {
    if(newOpenNode == 0 || parentNode == 0) return ;
    if(newOpenNode->getCol() == 6 && newOpenNode->getRow() == 3) {
        int i = 0;
    }
    newOpenNode->setG( parentNode->getG() + 10);
    newOpenNode->setH( ( abs((m_pEndNode->getRow() - newOpenNode->getRow())) + abs((m_pEndNode->getCol() - newOpenNode->getCol())) - 1) * 10);
    newOpenNode->setF(newOpenNode->getG() + newOpenNode->getH());
}

AStartNode *AstartMap::_getMinFstartNode() {
    _heapSort(m_openNode, m_openNode.size());
    int icount = m_openNode.size();
    AStartNode *minNode = m_openNode[0];
    return minNode;
}

void AstartMap::_heapRebuild(std::vector<AStartNode *> &rStartNodeArray, int root, int size)
{
    int child = 2 * root + 1;
    if(child <= size - 1) {
        int rightChild = child + 1;
        if(rightChild <= size - 1)
            if(rStartNodeArray[child]->getF() < rStartNodeArray[rightChild]->getF())
                child = rightChild;
        if(rStartNodeArray[root]->getF() < rStartNodeArray[child]->getF())
        {
            AStartNode *temp = rStartNodeArray[child];
            rStartNodeArray[child] = rStartNodeArray[root];
            rStartNodeArray[root] = temp;
            _heapRebuild(rStartNodeArray, child, size);
        }
    }
}  

void AstartMap::_heapSort(std::vector<AStartNode *> &rStartNodeArray, int size)
{
    for(int i = size-1; i >= 0; i--){
        _heapRebuild(rStartNodeArray,i,size);
    }  

    int last=size-1;
    for(int i = 1;i <= size; i++, last--) {
        AStartNode *temp=rStartNodeArray[0];
        rStartNodeArray[0]=rStartNodeArray[last];
        rStartNodeArray[last]=temp;
        _heapRebuild(rStartNodeArray,0,last);
    }
}
//
bool isNum(int inum) { // if the num in(0-9) return true, or return false
    if(inum >= 0 && inum <= 9) return true;
    return false;
}

速度和精确度之间的选择前不是静态的。你可以基于CPU的速度、用于路径搜索的时间片数、地图上物体(units)的数量、物体的重要性、组(group)的大小、难度或者其他任何因素来进行动态的选择。取得动态的折衷的一个方法是,建立一个启发式函数用于假定通过一个网格空间的最小代价是1,然后建立一个代价函数(cost
function)用于测量(scales):

g’(n) = 1 + alpha * ( g(n) – 1 )

如果alpha是0,则改进后的代价函数的值总是1。这种情况下,地形代价被完全忽略,A*工作变成简单地判断一个网格可否通过。如果alpha是1,则最初的代价函数将起作用,然后你得到了A*的所有优点。你可以设置alpha的值为0到1的任意值。

你也可以考虑对启发式函数的返回值做选择:绝对最小代价或者期望最小代价。例如,如果你的地图大部分地形是代价为2的草地,其它一些地方是代价为1的道路,那么你可以考虑让启发式函数不考虑道路,而只返回2*距离。

速度和精确度之间的选择并不是全局的。在地图上的某些区域,精确度是重要的,你可以基于此进行动态选择。例如,假设我们可能在某点停止重新计算路径或者改变方向,则在接近当前位置的地方,选择一条好的路径则是更重要的,因此为何要对后续路径的精确度感到厌烦?或者,对于在地图上的一个安全区域,最短路径也许并不十分重要,但是当从一个敌人的村庄逃跑时,安全和速度是最重要的。

在游戏中,路径潜在地花费了许多存储空间,特别是当路径很长并且有很多物体需要寻路时。路径压缩,导航点和beacons通过把多个步骤保存为一个较小数据从而减少了空间需求。Waypoints rely on straight-line segments being common so that
we have to store only the endpoints, while beacons rely on there being well-known paths calculated beforehand between specially marked places on the map.如果路径仍然用了许多存储空间,可以限制路径长度,这就回到了经典的时间-空间折衷法:为了节省空间,信息可以被丢弃,稍后才重新计算它。

时间: 2024-10-28 16:27:57

Cocos2d-x 3.1.1 学习日志16--A星算法(A*搜寻算法)的学习的相关文章

Cocos2d-x 3.1.1 学习日志13--CocosStudio学习必看

听说Cocos Studio很久了,主要是因为骨骼动画.目前看来Cocos2d-x播放动画的方式只有2种: 第一种:是播放序列帧动画,即将动画的每一帧都加载进缓存里,需要播放时再使用Animation类来播放,这种方法简单暴力,应对一些细节要求低的动画场景的时候,这么干无伤大雅.但是当动画帧数稍高的时候就会需要大量的图片,消耗资源很大. 第二种:是由Cocos2d-x提供的Action类来播放动画,这种动画是在帧循环中靠调整每次渲染的坐标来打到动画效果,由于帧循环是1/60秒刷新一次,会让这样播

Cocos2d-x 3.1.1 学习日志11--一Windows下Android环境搭建(一定对你有用的!!)

安装步骤::(多么痛的领悟!!) 1. 配置JDK JDK下载地址: 设置环境变量: JAVA_HOME=C:\Program Files (x86)\Java\jdk1.7.0_21 CLASSPATH=.;%JAVA_HOME%\lib; Path增加%JAVA_HOME%\bin; 设置完后打开cmd,输入java -version 如果出现下面提示,表明环境变量设置成功: C:\Users\arlin>java -version java version "1.7.0_21&quo

cocos2d-x学习日志(18) --程序是如何开始运行与结束?

问题的由来 怎么样使用 Cocos2d-x 快速开发游戏,方法很简单,你可以看看其自带的例程,或者从网上搜索教程,运行起第一个HelloWorld,然后在 HelloWorld 里面写相关逻辑代码,添加我们的层.精灵等 ~ 我们并不一定需要知道 Cocos2d-x 是如何运行或者在各种平台之上运行,也不用知道 Cocos2d-x 的游戏是如何运行起来的,它又是如何渲染界面的 ~~~ 两个入口 程序入口的概念是相对的,AppDelegate 作为跨平台程序入口,在这之上做了另一层的封装,封装了不同

Cocos2d-x 3.1.1 学习日志13--物理引擎登峰造极之路

cocos2dx在设计之初就集成了两套物理引擎,它们是box2d和chipmunk.我目前使用的是最新版的cocos2dx 3.1.1.引擎中默认使用的是chipmunk,如果想要改使用box2d的话,需要修改对应的android工程或者是ios工程的配置文件. 在2.x版本的cocos中,使用物理引擎的步骤十分繁琐.但在3.x版本中变得非常方便了.我这次的学习目标是制作一个打砖块的小游戏. 首先,现在的Scene类提供了一个静态工厂方法,用以创造一个集成物理引擎的场景. Scene::init

一个新菜鸟的ACM 感想及学习日志

感想:忘记了是什么时候喜欢上ACM的,也许是被坑上来的,也许是自己默默地喜欢上的.我忘不了第一次来我们学校的培训基地的时候,打的是洪菊学姐(虽然她不是ACMer)的电话,第一个见到的是我们集训队的队长周海.第一次敲成功的代码是军哥教会我敲得算1-50的累加.第一次训练是军训完之后国庆假期期间.那一周之后,我从从来没接触过编程语言到一个学期都不用担心C语言了! 本来老师宣传ACM的时候,我是想和班上的胡灿明(数学不错).左太平(英语大神)组一个队的,但是他们都表示对这个没兴趣.国庆后,跟花姐谈了谈

mysql学习日志

Mysql学习日志; 安装:Linux :yum install mysql* -y 验证Mysql是否正常安装:mysqladmin --version 进入 Mysql,要先启动#service mysqld start#mysql 更换Mysql初始密码: 安装完成mysql为空密码,修改密码方式:mysqladmin -u root password newpassword 用户已经有旧密码的更改方式:MYSQLADMIN -u root -p'oldpassword' PASSWORD

Cocos2d-x 3.1.1 学习日志15--getContentSize和getContentSizeInPixels区别

cocos2d-x中使用getContentSize获得的就是逻辑点的大小,而getContentSizeInPixels获得的就是像素点的大小. 像素点和逻辑点的对应关系为:逻辑点的大小 = 像素大小 / contentScaleFactor. 如果在高分辨率的平台上(如Iphone4),使用非高分辨率的图片资源,且设置contentScaleFactor为1.0,则IOS的Core Animation compositor 会自动拉伸非高分辨率的资源来适配, 使其在非高分辨率和高分辨率设备上

JAVA学习日志——Ajax和Json

# JAVA学习日志--Ajax和Json # Ajax和Json在一个web项目中可以说是经常用到了,Ajax是一种用于创建快速动态网页的技术,而Json则是一种与语言无关的数据交换的格式.以下是个人在学习过程中的总结. 一.Ajax 1.同步与异步 在学习Ajax之前我们要先知道什么是同步,什么是异步. 同步现象:客户端发送请求到服务器端,当服务器返回响应之前,客户端都处于等待卡死状态. 异步现象:客户端发送请求到服务器端,无论服务器是否返回响应,客户端都可以随    意做其他事情,不会被卡

MobileForm控件的使用方式-用.NET(C#)开发APP的学习日志

今天继续Smobiler开发APP的学习日志,这次是做一个title.toolbar.侧边栏三种效果 样式一 一.          Toolbar 1.       目标样式 我们要实现上图中的效果,需要如下的操作: 2.       修改属性 a.         修改Mobile Form的Toolbar属性 获取窗体底部工具栏,打开集合编辑器,并点击“添加”,分别填写数据,如图 1.图 2: 图 1设置界面1 图 2设置界面2 b.         修改Mobile Form的Toolb