Cocos2d-x 3.1.1 學習日誌16--A星演算法(A*搜尋演算法)的學習,cocos2d-x16--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 AstartMapbool 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.如果路徑仍然用了許多儲存空間,可以限制路徑長度,這就回到了經典的時間-空間折衷法:為了節省空間的,資訊可以被丟棄,稍後才重新計算它。
因為一些需要要學習cocos2d-x相關知識用於項目開發指教學習的過程最好給點資源
cn.cocos2d-x.org/document
教個問題:學習android的cocos2d-x需要什知識(除了c++),有沒有什好的學習資料?
看java和引擎的sdk,還有上網找例子教程。