日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Cocos2d-x 寻路算法解析(一): 距离优先

發(fā)布時(shí)間:2024/8/26 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cocos2d-x 寻路算法解析(一): 距离优先 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

尋路這塊在游戲中一直很重要,花了點(diǎn)時(shí)間研究了下這個(gè)問題,主要參考的是《Data Structures For Game Programmers》,其他的算法用普通Console演示就行了,尋路算法還是用一個(gè)界面比較好,最近在學(xué)Cocos2d-x,就用它了。

1.效果圖

用到Cocos2d-x中的基本畫線段,畫矩形就行了,還有簡(jiǎn)單的sprite拖動(dòng)。這demo建了一個(gè)線條類,繼承CCNode,重寫draw方法就行了。在draw方法中簡(jiǎn)單地調(diào)用ccDrawColor4F函數(shù)來設(shè)置顏色,ccDrawLine來畫線條,非常容易,cocos2d-x這些函數(shù)封裝了opengles中的原始函數(shù),使用非常簡(jiǎn)單。sprite拖動(dòng)可以參考這篇文章《cocos2d-x Touch 事件應(yīng)用的一個(gè)例子 》
?


1.小人和紅色X都可以用鼠標(biāo)移動(dòng),移到上面的地圖上,表示尋路起點(diǎn)和終點(diǎn)。

2.Distance, Simple Heuristic, Complex Heuristic, A Star分別是4種尋路算法,點(diǎn)擊程序就會(huì)開始演示尋路過程。

3.地圖的格子點(diǎn)擊會(huì)加深顏色,總共4個(gè)等級(jí),白,灰,深灰,黑,表示該格子的通過難度,白色是1,灰是2,深灰是3,黑色是不可通過區(qū)域。

4.”+++”表示加快演示速度,”—”表示降低演示速度。

2. Breadth – First Search算法

顧名思義,有點(diǎn)像呼吸,一層層地?cái)U(kuò)展開來,這個(gè)時(shí)候隊(duì)列(Queue),stl中的deque就派上用場(chǎng)了。deque不懂可以參考這篇文章《C++ Queue Example Rearranging RailRoad Cars》
?


起點(diǎn)在中心,會(huì)先訪問它的第一個(gè)外圈,再是第二個(gè)?,F(xiàn)在我覺得它更像一顆石頭扔在水面上的效果。

下面是偽代碼:
?

  • BreadthFirst( Node )
  • Queue.Enqueue( Node )Mark( Node )
  • While( Queue.IsNotEmpty )
  • Process( Queue.Front )
  • For Each Child of Queue.Front
  • if NotMarked( Child )
  • Queue.Enqueue( Child )
  • Mark( Child )
  • end if
  • end For
  • Queue.Dequeue()
  • End While
  • End Function
  • 復(fù)制代碼


    遍歷一個(gè)樹或者圖都可以用這個(gè)方法。在我們這里遇到了點(diǎn)麻煩,因?yàn)槲覀兌贾佬苯堑木嚯x是根號(hào)2的倍數(shù),要比上下左右方向遠(yuǎn),因?yàn)閷ぢ?#xff0c;很重要的因素的距離的長(zhǎng)短。我們需要考慮距離這個(gè)因素了。

    3.Distance – First Search
    ?


    起點(diǎn)還在中心,這張圖顯示了每一格到中心的估算距離。如果依靠距離優(yōu)先的算法,下圖是尋路次序:
    ?


    所以我們定義了一個(gè)方向數(shù)組:
    ?

  • const int DIRECTION[8][2]={
  • {0,1},??//north
  • {1,0},??//east
  • {0,-1},??//south
  • {-1,0},??//west
  • {1,1},??//northeast
  • {1,-1},??//southeast
  • {-1,-1},??//southwest
  • {-1,1}??//northwest
  • };
  • 復(fù)制代碼


    這樣通過一個(gè)for循環(huán),就可以訪問它周圍一圈的格子了,而且是按照距離優(yōu)先了,上下左右優(yōu)先,斜角次些。

    因?yàn)槭堑貓D,我們這里簡(jiǎn)單定義了一個(gè)2維數(shù)組,非常簡(jiǎn)單用一個(gè)vector就可以模擬了,假定讀者熟悉stl中的vector和C++中的template,手機(jī)號(hào)交易平臺(tái)不熟悉可以參考這篇文章《STL Vector》和《C++ 基礎(chǔ)之 “模版函數(shù)”,”類模版”》

  • #ifndef ARRAY2D_H
  • #define ARRAY2D_H
  • #include <vector>
  • using namespace std;
  • template <class Datatype>
  • class Array2D{
  • public:
  • ? ? Array2D(int p_width, int p_height):m_array(p_width * p_height),
  • ? ?? ???m_width(p_width),m_height(p_height){
  • ? ? }
  • ? ? Datatype* Get(int p_x, int p_y)const{
  • ? ?? ???return m_array[p_y * m_width + p_x];
  • ? ? }
  • ? ? void Set(int p_x, int p_y, Datatype* data){
  • ? ?? ???m_array[p_y * m_width + p_x] = data;
  • ? ? }
  • ? ? int Size() const{
  • ? ?? ???return m_width * m_height;
  • ? ? }
  • ? ? int Width() const{
  • ? ?? ???return m_width;
  • ? ? }
  • ? ? int Height()const{
  • ? ?? ???return m_height;
  • ? ? }
  • private:
  • ? ? vector<Datatype*> m_array;
  • ? ? int m_width;
  • ? ? int m_height;
  • };
  • #endif
  • 復(fù)制代碼


    我們還定義了一個(gè)Cell類表示每一個(gè)格子:它有很多屬性,像位置,最短距離到這個(gè)Cell的Cell的位置,是否已經(jīng)處理過,到起點(diǎn)的距離,是否可以通過,還有就是這個(gè)Cell的權(quán)重,表示經(jīng)過難度。我們這里使用了一個(gè)從cocos2d-x中拷來的宏,這樣get和set方法就不用手寫了。
    ?

  • #ifndef _CELL_H
  • #define _CELL_H
  • #define SYNTHESIZE(varType, varName, funName)\
  • protected: varType varName;\
  • public: virtual varType get##funName(void) const { return varName; }\
  • public: virtual void set##funName(varType var){ varName = var; }
  • class Cell{
  • public:
  • ? ? Cell():_marked(false),_distance(0),_lastX(-1),_lastY(-1),
  • ? ?? ???_x(-1),_y(-1),_passable(true),_weight(1),_drawProgress(false){
  • ? ? }
  • ? ? SYNTHESIZE(int, _x, X);? ?? ?? ?? ?? ?? ?? ???//start at left bottom
  • ? ? SYNTHESIZE(int, _y, Y);? ?? ?? ?? ?? ?? ?? ???//start at left bottom
  • ? ? SYNTHESIZE(int, _lastX, LastX);? ?? ?? ?? ?? ?//store the nearest cell's location related this cell
  • ? ? SYNTHESIZE(int, _lastY, LastY);? ?? ?? ?? ?? ?//store the nearest cell's location related this cell
  • ? ? SYNTHESIZE(bool, _marked, Marked);? ?? ?? ?? ?//whether this cell process or not
  • ? ? SYNTHESIZE(float, _distance, Distance);? ?? ? //distance between this cell and start
  • ? ? SYNTHESIZE(bool, _passable, Passable);? ?? ???//whether this call can pass
  • ? ? SYNTHESIZE(int, _drawProgress, DrawProgress); //just for draw the path finding progress
  • ? ? inline void setWeight(int weight){
  • ? ?? ???if(weight > 4){
  • ? ?? ?? ?? ?_weight = 1;
  • ? ?? ???}else{
  • ? ?? ?? ?? ?_weight = weight;
  • ? ?? ?? ?? ?setPassable(weight == 4 ? false : true);
  • ? ?? ???}
  • ? ? }
  • ? ? inline int getWeight()const{ return _weight;}
  • private:
  • ? ? int _weight;? ?? ?? ?? ???//default is 1, 4 means this cell is impassable.
  • ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //distance have relationship with weight
  • };
  • #endif
  • 復(fù)制代碼


    核心算法如下:事先需要了解的知識(shí):因?yàn)槲覀冃枰凑兆疃叹嚯x優(yōu)先尋路,所以一個(gè)優(yōu)先隊(duì)列就需要了,這里簡(jiǎn)單地使用了heap,對(duì)heap不了解的可以看下這篇文章《HeapSort(堆排序 C++) 》,下面還用上了C++中的函數(shù)指針,可以參考這篇文章《C++ 函數(shù)指針 函數(shù)名作為參數(shù) 》,為什么要用函數(shù)指針呢?看完整個(gè)尋路算法系列你就知道了。

    語言解釋:

    先把起點(diǎn)Cell加入到heap中,對(duì)這個(gè)Cell的周圍8個(gè)Cell進(jìn)行處理,主要是更新他們到起點(diǎn)的距離和記錄最短距離到這個(gè)Cell的Cell的位置。每次找到一個(gè)新的Cell,

    1.如果還沒處理過,標(biāo)上處理過標(biāo)志,更新他們到起點(diǎn)的距離和記錄最短距離到這個(gè)Cell的Cell的位置,再把這個(gè)Cell加入到堆中,重新形成一個(gè)堆,這樣開始很容易得到離起點(diǎn)最近的點(diǎn)。

    2.如果處理過,看下新的距離是不是比老的距離短,如果短,更新上面的提到的兩點(diǎn)。

    不斷處理,直到訪問了所有的點(diǎn)或者找到終點(diǎn)了。

    下面是代碼:整個(gè)尋路算法的核心代碼。
    ?

  • typedef bool (*compareTwoCells)(Cell *c1, Cell *c2);
  • bool compareTwoCellsByDistance(Cell *c1, Cell *c2){
  • ? ? if(c1->getDistance() <= c2->getDistance()){
  • ? ?? ???return false;
  • ? ? }else{
  • ? ?? ???return true;
  • ? ? }
  • }
  • void HelloWorld::startPathFinding(compareTwoCells compareMethod, int startX,int startY,int goalX,int goalY){
  • ? ? Cell *startCell = _m_Map.Get(startX, startY);
  • ? ? vector<Cell*> vecCells;
  • ? ? vecCells.push_back(startCell);
  • ? ? make_heap(vecCells.begin(),vecCells.end(),compareMethod);
  • ? ? startCell->setMarked(true);
  • ? ? Cell *nowProcessCell;
  • ? ? while(vecCells.size() != 0){
  • ? ?? ???pop_heap(vecCells.begin(),vecCells.end(),compareMethod);
  • ? ?? ???nowProcessCell = vecCells.back();
  • ? ?? ???vecCells.pop_back();
  • ? ?? ???if(nowProcessCell->getX() == _goalX && nowProcessCell->getY() == _goalY){//the goal is reach
  • ? ?? ?? ?? ?return;
  • ? ?? ???}
  • ? ?? ???for(int i = 0; i < 8; ++i){ //check eight direction
  • ? ?? ?? ?? ?int indexX = nowProcessCell->getX() + DIRECTION[i][0];
  • ? ?? ?? ?? ?int indexY = nowProcessCell->getY() + DIRECTION[i][1];
  • ? ?? ?? ?? ?if(indexX >= 0 && indexX < xLineCount && indexY >= 0 && indexY < yLineCount
  • ? ?? ?? ?? ?? ? && _m_Map.Get(indexX,indexY)->getPassable() == true){//check is a OK cell or not
  • ? ?? ?? ?? ?? ?? ???Cell *cell = _m_Map.Get(indexX,indexY);
  • ? ?? ?? ?? ?? ?? ???float beforeDistance = DISTANCE[i] * cell->getWeight() + _m_Map.Get(nowProcessCell->getX(),
  • ? ?? ?? ?? ?? ?? ?? ?? ?nowProcessCell->getY())->getDistance();//calculate the distance
  • ? ?? ?? ?? ?? ?? ???if(cell->getMarked() == false){
  • ? ?? ?? ?? ?? ?? ?? ?? ?cell->setMarked(true);
  • ? ?? ?? ?? ?? ?? ?? ?? ?cell->setLastX(nowProcessCell->getX());
  • ? ?? ?? ?? ?? ?? ?? ?? ?cell->setLastY(nowProcessCell->getY());
  • ? ?? ?? ?? ?? ?? ?? ?? ?cell->setDistance(beforeDistance);
  • ? ?? ?? ?? ?? ?? ?? ?? ?vecCells.push_back(cell);//only push the unmarked cell into the vector
  • ? ?? ?? ?? ?? ?? ?? ?? ?push_heap(vecCells.begin(),vecCells.end(),compareMethod);
  • ? ?? ?? ?? ?? ?? ???}else{// if find a lower distance, update it
  • ? ?? ?? ?? ?? ?? ?? ?? ?if(beforeDistance < cell->getDistance()){
  • ? ?? ?? ?? ?? ?? ?? ?? ?? ? cell->setDistance(beforeDistance);
  • ? ?? ?? ?? ?? ?? ?? ?? ?? ? cell->setLastX(nowProcessCell->getX());
  • ? ?? ?? ?? ?? ?? ?? ?? ?? ? cell->setLastY(nowProcessCell->getY());
  • ? ?? ?? ?? ?? ?? ?? ?? ?? ? make_heap(vecCells.begin(),vecCells.end(),compareMethod);//distance change,so make heap again
  • ? ?? ?? ?? ?? ?? ?? ?? ?}
  • ? ?? ?? ?? ?? ?? ???}
  • ? ?? ?? ?? ?}
  • ? ?? ???}
  • ? ? }
  • }
  • startPathFinding(compareTwoCellsByDistance,_playerX,_playerY,_goalX,_goalY);//demo
  • 復(fù)制代碼


    4.尋路動(dòng)態(tài)圖:
    ?


    我只是簡(jiǎn)單地在起點(diǎn)和終點(diǎn)間加入了一個(gè)不可通過的墻,通過查看藍(lán)色的區(qū)域會(huì)發(fā)現(xiàn)這個(gè)算法很慢。目標(biāo)在右邊,這個(gè)算法上下左右都找,雖然找到了也太浪費(fèi)資源了吧?下篇我們來看看其他的尋路算法。

    總結(jié)

    以上是生活随笔為你收集整理的Cocos2d-x 寻路算法解析(一): 距离优先的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。