日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2024/8/26 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cocos2d-x 寻路算法解析(一): 距离优先 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

1.效果圖

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


1.小人和紅色X都可以用鼠標移動,移到上面的地圖上,表示尋路起點和終點。

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

3.地圖的格子點擊會加深顏色,總共4個等級,白,灰,深灰,黑,表示該格子的通過難度,白色是1,灰是2,深灰是3,黑色是不可通過區域。

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

2. Breadth – First Search算法

顧名思義,有點像呼吸,一層層地擴展開來,這個時候隊列(Queue),stl中的deque就派上用場了。deque不懂可以參考這篇文章《C++ Queue Example Rearranging RailRoad Cars》
?


起點在中心,會先訪問它的第一個外圈,再是第二個。現在我覺得它更像一顆石頭扔在水面上的效果。

下面是偽代碼:
?

  • 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
  • 復制代碼


    遍歷一個樹或者圖都可以用這個方法。在我們這里遇到了點麻煩,因為我們都知道斜角的距離是根號2的倍數,要比上下左右方向遠,因為尋路,很重要的因素的距離的長短。我們需要考慮距離這個因素了。

    3.Distance – First Search
    ?


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


    所以我們定義了一個方向數組:
    ?

  • 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
  • };
  • 復制代碼


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

    因為是地圖,我們這里簡單定義了一個2維數組,非常簡單用一個vector就可以模擬了,假定讀者熟悉stl中的vector和C++中的template,手機號交易平臺不熟悉可以參考這篇文章《STL Vector》和《C++ 基礎之 “模版函數”,”類模版”》

  • #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
  • 復制代碼


    我們還定義了一個Cell類表示每一個格子:它有很多屬性,像位置,最短距離到這個Cell的Cell的位置,是否已經處理過,到起點的距離,是否可以通過,還有就是這個Cell的權重,表示經過難度。我們這里使用了一個從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
  • 復制代碼


    核心算法如下:事先需要了解的知識:因為我們需要按照最短距離優先尋路,所以一個優先隊列就需要了,這里簡單地使用了heap,對heap不了解的可以看下這篇文章《HeapSort(堆排序 C++) 》,下面還用上了C++中的函數指針,可以參考這篇文章《C++ 函數指針 函數名作為參數 》,為什么要用函數指針呢?看完整個尋路算法系列你就知道了。

    語言解釋:

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

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

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

    不斷處理,直到訪問了所有的點或者找到終點了。

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

  • 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
  • 復制代碼


    4.尋路動態圖:
    ?


    我只是簡單地在起點和終點間加入了一個不可通過的墻,通過查看藍色的區域會發現這個算法很慢。目標在右邊,這個算法上下左右都找,雖然找到了也太浪費資源了吧?下篇我們來看看其他的尋路算法。

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。