在许多游戏程序中有自动寻路的功能,自动寻路包括最短路径和自动避障两个方面,这里将自动避障抽象出来就是常见的迷宫求解问题。
如下图迷宫,黑色为障碍,白色为可通行,现在要从左上角到右下角自动寻路。
要解决这个问题,分析一下和我们人为解决问题的思路一样,先寻一条路,此路不通再返回到某一个分叉寻另外一条路,自然想到使用栈结构。我们判断当前所在位置是够可通行,如果可通行则将其压入栈,如果不能通行则相对于栈顶元素换一个方向再尝试直到相对栈顶元素的4个方向都不能通行,此时说明这个栈顶元素一定不是寻路路径上的点,将其出栈,再相对于栈顶元素寻路。
这里要注意的是,已经走过的点必须判定为不能通行,否则整个计算过程会发生原地循环的状况。
//定义小方格坐标形式 typedef struct { int xPos; //当前X坐标,从0开始 int yPos; //当前Y坐标,从0开始 }SQUARE_POS; //定义从当前坐标走向下一个方格的方向 typedef enum { RIGHT=0, DOWN, LEFT, UP }SQUARE_DIR; //定义迷宫求解的栈元素类型 typedef struct { SQUARE_POS pos; SQUARE_DIR dirNext; //当前坐标走向下一个方格的移动方向,记录当前已经搜索的方向 } JWArrayElem;
寻路核心程序如下
/** *功能:计算当前地图的寻路路径栈 *参数:map--地图 * posStart--起始寻路点 * posEnd--寻路目标点 * pResultArray--计算得到当前地图的寻路路径栈 *返回:寻路成功返回TRUE,寻路失败返回假 *其他:2014/04/16 By Jim Wen Ver1.0 **/ JWArray_BOOL MazePath(const WORD *map, const SQUARE_POS posStart, const SQUARE_POS posEnd, JWArray *pResultArray) { SQUARE_POS curPos; JWArrayElem eTop; int nFootPrint[WORK_SQUARE_HEIGHT][WORK_SQUARE_WIDTH]; int i, j; //初始化已经已经走过的地图坐标(i ,j)(走过的为0,没有走过的为1) for (i = 0 ; i < WORK_SQUARE_HEIGHT; i++) { for (j = 0; j < WORK_SQUARE_WIDTH; j++) { nFootPrint[i][j] = 1; } } //清空栈 JWArrayMakeEmpty(pResultArray); //从起始位置开始寻路 curPos = posStart; do { if (JWARRAY_TRUE == IsPass(map, nFootPrint, curPos))//当前位置可通 { //当前位置入栈 eTop.pos = curPos; eTop.dirNext = RIGHT; JWArrayPush(pResultArray, eTop); //设为已经走过 nFootPrint[curPos.yPos][curPos.xPos] = 0; //若是出口位置则寻路完成 if (curPos.xPos == posEnd.xPos && curPos.yPos == posEnd.yPos) { return JWARRAY_TRUE; } //下一个搜索方块切换当前位置为右相邻的方块位置 curPos.xPos += 1; } else//当前位置不可通 { JWArrayGetTop(pResultArray, &eTop); if(UP != eTop.dirNext)//栈顶元素还有其他方向没有搜索 { CalcNextPos(pResultArray, &curPos); } else//栈顶元素所有方向都已经搜索完毕 { JWArrayPop(pResultArray, NULL); } } } while (JWARRAY_FALSE == JWArrayIsEmpty(pResultArray)); //遍历完所有的方格还没有找到路则判定为寻路失败 return JWARRAY_FALSE; }
运行程序,先求解成功后绘制求解路径如下
完整程序下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219