最近搞MTK斯凱冒泡平台的游戲開發,碰到了自動尋路的問題,很多程序員都知道A*算法,既簡單有使用! 所以我也選擇了A*算法,由於時間比較緊,就在網上百度此算法的C實現,確實有很多! 但經測試都有不同的問題,並不能用在商業游戲中,所以最後決定還是自己寫吧! A*原理 比較簡單,網上有很多介紹的!我也是在網上看的,這裡就不重復了! 由於我是Java程序員剛開始搞嵌入式C開發不久,所以有很多C用法不是很熟悉,通過搞這個算法又知道不少知識 比如 Java裡的集合 C裡要用鏈表 這也是此算法比較重要的一個技術點,遍歷鏈表,還有刪減節點,這些對於C程序員來說應該都是很簡單的事情, 這裡還是說一下,以便那些從JAVA轉入C開發的程序員快速理解 PS: 這裡使用的是 前插式單向鏈表
- typedef struct Node
- {//節點結構體
- int f,g,h;
- int row; //該節點所在行
- int col; //該節點所在列
- int direction;//parent節點要移動的方向就能到達本節點
- struct Node * parent;
- }Node, *Lnode;
- typedef struct Stack
- {//OPEN CLOSED 表結構體
- Node * npoint;
- struct Stack * next;
- }Stack, *Lstack;
- void PutintoOpen(Node * suc )
- {//把節點放入OPEN 或CLOSED 表中
- Stack * temp;
- temp =(Stack *) malloc(sizeof(Stack));
- temp->npoint = suc;
- temp->next = Open->next;
- Open->next = temp;
- }
- Node * getNodeFromOpen()
- {//選取OPEN表上f值最小的節點,返回該節點地址
- Lstack temp = Open->next,min = Open->next,minp = Open;
- Node * minx;
- if( temp == NULL )
- return NULL;
- while(temp->next != NULL)
- {
- if( (temp->next ->npoint->f) < (min->npoint->f) )
- {
- min = temp->next;
- minp = temp;
- }
- temp = temp->next;
- }
- minx = min->npoint;
- temp = minp->next;
- minp->next = minp->next->next;
- free(temp);
- return minx;
- }
- Node * BelongInOpen( Node * suc )
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Open -> next ;
- if(temp == NULL)
- return NULL;
- while( temp != NULL )
- {
- if( Equal(suc,temp->npoint) )
- {
- return temp -> npoint;
- }
- else
- {
- temp = temp->next;
- }
- }
- return NULL;
- }
好了,鏈表的操作基本講完了! 接下來的全部代碼應該都比較好理解,整個算法的演示程序僅有一個 .c文件即可,您可以在TC, VC6, C-Free5 下編譯通過! A*算法 C語言實現的代碼示例
- //正序遍歷鏈表
- void printfOpenData()
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Open -> next;
- Node *p_node;
- if(temp == NULL)
- return;
- while(temp != NULL)
- {
- Lstack head = temp;
- temp = temp->next;
- p_node = head->npoint;
- printf("Open庫數據![%d,%d]\n", p_node->col, p_node->row );
- free(p_node);
- free( head );
- Open->next = temp;
- }
- printf("\n Open庫數據 數據全部清楚 \n");
- return;
- }
本程序很容易修改成您工程需要的形式,比如 我的使用方式是這樣的
- /*******************************************************************************
- * CopyRight (c) HYTC Ltd. All rights reserved.
- * Filename: main.c
- * Creator: GaoLei
- * Version: 0.0
- * Date: 2011-06-15
- * QQ: 38929568
- * Description: A*尋路算法 測試類
- *******************************************************************************/
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #define FALSE 0
- #define TRUE 1
- #define NULL 0
- typedef int BOOL;
- int map[20][20] =
- {
- { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
- { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- };
- typedef struct Node
- {//節點結構體
- int f,g,h;
- int row; //該節點所在行
- int col; //該節點所在列
- int direction;//parent節點要移動的方向就能到達本節點
- struct Node * parent;
- }Node, *Lnode;
- typedef struct Stack
- {//OPEN CLOSED 表結構體
- Node * npoint;
- struct Stack * next;
- }Stack, *Lstack;
- int rows = 20; //地圖行數
- int cols = 20; //地圖列數
- int G_OFFSET = 1; //每個圖塊G值的增加值
- int destinationRow; //目標所在行
- int destinationCol; //目標所在列
- int canMoveIndex = 0; //可以通行的地圖圖塊索引
- int tileSize = 1; //圖塊大小
- Lstack Open = NULL;
- Lstack Closed = NULL;
- Node * getNodeFromOpen()
- {//選取OPEN表上f值最小的節點,返回該節點地址
- Lstack temp = Open->next,min = Open->next,minp = Open;
- Node * minx;
- if( temp == NULL )
- return NULL;
- while(temp->next != NULL)
- {
- if( (temp->next ->npoint->f) < (min->npoint->f) )
- {
- min = temp->next;
- minp = temp;
- }
- temp = temp->next;
- }
- minx = min->npoint;
- temp = minp->next;
- minp->next = minp->next->next;
- free(temp);
- return minx;
- }
- BOOL Equal(Node * suc,Node * goal)
- {//判斷節點是否相等,相等,不相等
- if ( (suc->row == goal->row) && (suc->col == goal->col) )
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- Node * BelongInOpen( Node * suc )
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Open -> next ;
- if(temp == NULL)
- return NULL;
- while( temp != NULL )
- {
- if( Equal(suc,temp->npoint) )
- {
- return temp -> npoint;
- }
- else
- {
- temp = temp->next;
- }
- }
- return NULL;
- }
- Node * BelongInClosed( Node * suc )
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Closed -> next ;
- if(temp == NULL)
- return NULL;
- while(temp != NULL)
- {
- if( Equal(suc,temp->npoint) )
- {
- return temp -> npoint;
- }
- else
- {
- temp = temp->next;
- }
- }
- return NULL;
- }
- void PutintoOpen(Node * suc )
- {//把節點放入OPEN 或CLOSED 表中
- Stack * temp;
- temp =(Stack *) malloc(sizeof(Stack));
- temp->npoint = suc;
- temp->next = Open->next;
- Open->next = temp;
- }
- void PutintoClosed(Node * suc )
- {//把節點放入OPEN 或CLOSED 表中
- Stack * temp;
- temp =(Stack *) malloc(sizeof(Stack));
- temp->npoint = suc;
- temp->next = Closed->next;
- Closed->next = temp;
- }
- //得到該圖塊的H值
- int getH(int row, int col)
- {
- return (abs(destinationRow - row) + abs(destinationCol - col));
- }
- //得到該位置所在地圖行
- int getRowPosition(int y)
- {
- return (y / tileSize);
- }
- //得到該位置所在地圖列
- int getColPosition(int x)
- {
- return (x / tileSize);
- }
- //檢測該圖塊是否可通行
- BOOL isCanMove(int col, int row)
- {
- if(col < 0 || col >= cols)
- return FALSE;
- if(row < 0 || row >= rows)
- return FALSE;
- return map[col][row] == canMoveIndex;
- }
- Node* checkOpen(int row, int col)
- {
- Lstack temp = Open -> next;
- if ( temp == NULL )
- return NULL;
- while (temp != NULL)
- {
- if ( (temp->npoint->row==row) && (temp->npoint->col == col) )
- {
- return temp -> npoint;
- }
- else
- {
- temp = temp->next;
- }
- }
- return NULL;
- }
- BOOL isInClose(int row, int col)
- {
- Lstack temp = Closed -> next;
- if ( temp == NULL )
- return FALSE;
- while (temp != NULL)
- {
- if ( (temp->npoint->row==row) && (temp->npoint->col == col) )
- {
- return TRUE;
- }
- else
- {
- temp = temp->next;
- }
- }
- return FALSE;
- }
- int directionIndex =0;
- int direction[256];
- void creatSeccessionNode(Node *bestNode, int row, int col)
- {
- int g = bestNode->g + G_OFFSET;
- if(!isInClose(row, col))
- {
- Node *oldNode = NULL;
- if((oldNode = checkOpen(row, col)) != NULL)
- {
- if(oldNode->g < g)
- {
- oldNode->parent = bestNode;
- oldNode->g = g;
- oldNode->f = g + oldNode->h;
- }
- }
- else
- {
- Node *node = (Node *) malloc(sizeof(Node));
- node->parent = bestNode;
- node->g = g;
- node->h = getH(row, col);
- node->f = node->g + node->h;
- node->row = row;
- node->col = col;
- directionIndex++;
- node->direction = directionIndex;
- // openNode.addElement(node);
- PutintoOpen( node );
- }
- }
- }
- /**
- * 根據傳入的節點生成子節點
- * @param bestNode
- * @param destinationRow
- * @param destinationCol
- */
- void seachSeccessionNode(Node *bestNode)
- {
- int row, col;
- // Node *bestNodeInOpen = NULL;
- //上部節點
- if(isCanMove(row = bestNode->row - 1, col = bestNode->col))
- {
- creatSeccessionNode(bestNode, row, col);
- }
- //下部節點
- if(isCanMove(row = bestNode->row + 1, col = bestNode->col))
- {
- creatSeccessionNode(bestNode, row, col);
- }
- //左部節點
- if(isCanMove(row = bestNode->row, col = bestNode->col - 1))
- {
- creatSeccessionNode(bestNode, row, col);
- }
- //右部節點
- if(isCanMove(row = bestNode->row, col = bestNode->col + 1))
- {
- creatSeccessionNode(bestNode, row, col);
- }
- PutintoClosed( bestNode );
- }
- //正序遍歷鏈表
- void printfOpenData()
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Open -> next;
- Node *p_node;
- if(temp == NULL)
- return;
- while(temp != NULL)
- {
- Lstack head = temp;
- temp = temp->next;
- p_node = head->npoint;
- printf("Open庫數據![%d,%d]\n", p_node->col, p_node->row );
- free(p_node);
- free( head );
- Open->next = temp;
- }
- printf("\n Open庫數據 數據全部清楚 \n");
- return;
- }
- void printfClosedData()
- {//判斷節點是否屬於OPEN表或CLOSED表,是則返回節點地址,否則返回空地址
- Lstack temp = Closed -> next ;
- Node *p_node;
- if(temp == NULL)
- return;
- while(temp != NULL)
- {
- Lstack head = temp;
- temp = temp->next;
- p_node = head->npoint;
- printf("Closed庫數據![%d,%d]\n", p_node->col, p_node->row );
- free(p_node);
- free( head );
- Closed -> next = temp;
- }
- printf("\n Closed庫數據 數據全部清楚 \n");
- /*
- temp = Closed -> next;
- while(temp != NULL)
- {
- printf("Closed庫數據!節點");
- temp = temp->next;
- }*/
- return;
- }
- void getPath(int startX, int StartY, int destinationX, int destinationY)
- {
- Node *startNode = (Node *) malloc(sizeof(Node));
- Node *bestNode = NULL;
- int index = 0;
- destinationRow = getRowPosition(destinationY);
- destinationCol = getColPosition(destinationX);
- startNode->parent= NULL;
- startNode->row = getRowPosition(StartY);
- startNode->col = getColPosition(startX);
- startNode->g = 0;
- startNode->h = getH( startNode->row, startNode->col );
- startNode->f = startNode->g + startNode->h;
- startNode->direction = 0;
- PutintoOpen( startNode );// openNode.add(startNode);
- while(TRUE)
- {
- bestNode = getNodeFromOpen(); //從OPEN表中取出f值最小的節點
- if(bestNode == NULL)//未找到路徑
- {
- printf("未找到路徑\n");
- return;
- }
- else if(bestNode->row == destinationRow
- && bestNode->col == destinationCol )
- {
- Node *_Node = bestNode;
- int nodeSum = 0;
- int nodeIndex =0;
- printf("程序運行次數=%d\n",index);
- while( _Node->parent != NULL )
- {
- printf("x:%d y:%d direction = %d \n", _Node->col, _Node->row, _Node->direction );
- _Node = _Node->parent;
- nodeSum += 1;
- }
- printf("節點數量=%d\n",nodeSum);
- _Node = bestNode;
- nodeIndex = nodeSum-1;
- while( _Node->parent != NULL && nodeIndex>=0)
- {
- Node *_NodeParent = _Node->parent;
- printf("x:%d y:%d direction = %d \n", _Node->col, _Node->row, _Node->direction );
- if( _NodeParent->col - _Node->col == 0 && _NodeParent->row - _Node->row == +1 )
- {//從父節點到本節點的操作是 上
- direction[nodeIndex] = 1;
- }
- else if( _NodeParent->col - _Node->col == 0 && _NodeParent->row - _Node->row == -1 )
- {//從父節點到本節點的操作是 下
- direction[nodeIndex] = 2;
- }
- else if( _NodeParent->col - _Node->col == +1 && _NodeParent->row - _Node->row == 0 )
- {//從父節點到本節點的操作是 左
- direction[nodeIndex] = 3;
- }
- else if( _NodeParent->col - _Node->col == -1 && _NodeParent->row - _Node->row == 0 )
- {//從父節點到本節點的操作是 右
- direction[nodeIndex] = 4;
- }
- else
- {
- direction[nodeIndex] = 0;
- }
- nodeIndex -= 1;
- _Node = _Node->parent;
- }
- for( nodeIndex=0; nodeIndex<nodeSum; nodeIndex++ )
- {
- printf("direction[%d]=%d\n",nodeIndex,direction[nodeIndex]);
- }
- return ;
- }
- index++;
- seachSeccessionNode(bestNode);
- }
- }
- void main()
- {//主函數
- //初始操作,建立open和closed表
- Open = (Stack *) malloc(sizeof(Stack));
- Open->next = NULL;
- Closed = (Stack *) malloc(sizeof(Stack));
- Closed->next = NULL;
- //-----------------------------------
- getPath( 0, 0, 19, 19 );
- printf("程序認定該起始狀態無法道達目標狀態!\n");
- printfOpenData();
- printfClosedData();
- free(Open);
- free(Closed);
- //--------------------------------------
- }
這樣的目的是 將地圖數據 以及當前位置,和目標位置傳遞個 自動尋路方法 還需要修改 能否通過的方法,可以根據自己的地圖來做處理
- //將main() 方法改成
- void autoPathfinding( uint16 *MD, uint8 map_w, uint8 map_h, int16 startX, int16 startY, int16 destinationX, int16 destinationY )
PS: 看源代碼的時候,如果你覺得有些變量定義的位置不舒服,是因為我的嵌入式C所用的環境要求,當然您可以根據您的環境自由修改! 時間關系,並沒有特別優化,如果您有好的優化方案,我願意聆聽!
- //檢測該圖塊是否可通行
- BOOL isCanMove(int col, int row)
- {
- if(col < 0 || col >= cols)
- return FALSE;
- if(row < 0 || row >= rows)
- return FALSE;
- //return map[col][row] == canMoveIndex;
- return isCanGoByMapTile( MapData[ (col)*rows+(row) ] );
- }
本文出自 “鍵碼視窗” 博客,請務必保留此出處http://kome2000.blog.51cto.com/969562/590579