NAV导航网格寻路(6) -- 寻路实现

来源:互联网 发布:动漫绘图软件 编辑:程序博客网 时间:2024/04/30 05:15

这篇是转的文章,原文 http://blianchen.blog.163.com/blog/static/13105629920103911258517/

 

前面已经介绍了寻路的方法,现在给出我的一个实现。

A*寻找网格路径

A*算法就不说了,网上很多,这里只说下三角形网格如何使用A*算法,如下图,绿色直线代表最终路径和方向,路径线进入三角形的边称为穿入边,路径线出去的边称为穿出边。每个三角形的花费(g值)采用穿入边和穿出边的中点的距离(图中红线),至于估价函数(h值)使用该三角形的中心点(3个顶点的平均值)到路径终点的x和y方向的距离。

 

下面只贴出关键代码

复制代码
private var m_CellVector:Vector.<Cell>;           private var openList:Heap;     //二叉堆         private var closeList:Array; /**         * 构建网格路径,该方法生成closeList         * @param startCell 起始点所在网格         * @param startPos 起始点坐标         * @param endCell 终点所在网格         * @param endPos 终点坐标         * @return          */ public function buildPath(startCell:Cell, startPos:Vector2f,                                   endCell:Cell, endPos:Vector2f):void{            openList.clear();            closeList.length = 0;                        openList.put(endCell);            endCell.f = 0;            endCell.h = 0;            endCell.isOpen = false;            endCell.parent = null;            endCell.sessionId = pathSessionId;                        var foundPath:Boolean = false;        //是否找到路径            var currNode:Cell;                //当前节点            var adjacentTmp:Cell = null;    //当前节点的邻接三角型            while (openList.size > 0) {                // 1. 把当前节点从开放列表删除, 加入到封闭列表                currNode = openList.pop();                closeList.push(currNode);                                //路径是在同一个三角形内                if (currNode == startCell) {                    foundPath = true;                    break;                }                                // 2. 对当前节点相邻的每一个节点依次执行以下步骤:                //所有邻接三角型                var adjacentId:int;                for (var i:int=0; i<3; i++) {                    adjacentId = currNode.links[i];                    // 3. 如果该相邻节点不可通行或者该相邻节点已经在封闭列表中,                    //    则什么操作也不执行,继续检验下一个节点;                    if (adjacentId < 0) {                        //不能通过                        continue;                    } else {                        adjacentTmp = m_CellVector[adjacentId];            //m_CellVector 保存所有网格的数组                    }                                        if (adjacentTmp != null) {                        if (adjacentTmp.sessionId != pathSessionId) {                            // 4. 如果该相邻节点不在开放列表中,则将该节点添加到开放列表中,                             //    并将该相邻节点的父节点设为当前节点,同时保存该相邻节点的G和F值;                            adjacentTmp.sessionId = pathSessionId;                            adjacentTmp.parent = currNode;                            adjacentTmp.isOpen = true;                                                        //H和F值                            adjacentTmp.computeHeuristic(startPos);                     //m_WallDistance 是保存三角形各边中点连线的距离,共3个                            adjacentTmp.f = currNode.f + adjacentTmp.m_WallDistance[Math.abs(i - currNode.m_ArrivalWall)];                                                        //放入开放列表并排序                            openList.put(adjacentTmp);                                                        // remember the side this caller is entering from                            adjacentTmp.setAndGetArrivalWall(currNode.index);                        } else {                            // 5. 如果该相邻节点在开放列表中,                             //    则判断若经由当前节点到达该相邻节点的G值是否小于原来保存的G值,                            //    若小于,则将该相邻节点的父节点设为当前节点,并重新设置该相邻节点的G和F值                            if (adjacentTmp.isOpen) {//已经在openList中                                if (currNode.f + adjacentTmp.m_WallDistance[Math.abs(i - currNode.m_ArrivalWall)] < adjacentTmp.f) {                                    adjacentTmp.f = currNode.f;                                    adjacentTmp.parent = currNode;                                                                        // remember the side this caller is entering from                                    adjacentTmp.setAndGetArrivalWall(currNode.index);                                }                            } else {//已在closeList中                                adjacentTmp = null;                                continue;                            }                        }                    }                }            }}
复制代码

 

 

由close list取出网格路径

复制代码
/**         * 路径经过的网格         * @return          */                private function getCellPath():Vector.<Cell> {            var pth:Vector.<Cell> = new Vector.<Cell>();                        var st:Cell = closeList[closeList.length-1];            pth.push(st);                                    while (st.parent != null) {                pth.push(st.parent);                st = st.parent;            }            return pth;        }
复制代码

 

 

根据网格路径计算路径点

算法前面已经详细说明,以下是代码

 

复制代码
/**         * 根据经过的三角形返回路径点(下一个拐角点法)         * @param start          * @param end          * @return Point数组         */                private function getPath(start:Vector2f, end:Vector2f):Array {            //经过的三角形            var cellPath:Vector.<Cell> = getCellPath();            //没有路径            if (cellPath == null || cellPath.length == 0) {                return null;            }                        //保存最终的路径(Point数组)            var pathArr:Array = new Array();                        //开始点            pathArr.push(start.toPoint());                //起点与终点在同一三角形中            if (cellPath.length == 1) {                        pathArr.push(end.toPoint());    //结束点                return pathArr;            }                        //获取路点            var wayPoint:WayPoint = new WayPoint(cellPath[0], start);            while (!wayPoint.position.equals(end)) {                wayPoint = this.getFurthestWayPoint(wayPoint, cellPath, end);                pathArr.push(wayPoint.position);            }                        return pathArr;        }                /**         * 下一个拐点         * @param wayPoint 当前所在路点         * @param cellPath 网格路径         * @param end 终点         * @return          */                private function getFurthestWayPoint(wayPoint:WayPoint, cellPath:Vector.<Cell>, end:Vector2f):WayPoint {            var startPt:Vector2f = wayPoint.position;    //当前所在路径点            var cell:Cell = wayPoint.cell;            var lastCell:Cell = cell;            var startIndex:int = cellPath.indexOf(cell);    //开始路点所在的网格索引            var outSide:Line2D = cell.sides[cell.m_ArrivalWall];    //路径线在网格中的穿出边            var lastPtA:Vector2f = outSide.getPointA();            var lastPtB:Vector2f = outSide.getPointB();            var lastLineA:Line2D = new Line2D(startPt, lastPtA);            var lastLineB:Line2D = new Line2D(startPt, lastPtB);            var testPtA:Vector2f, testPtB:Vector2f;        //要测试的点            for (var i:int=startIndex+1; i<cellPath.length; i++) {                cell = cellPath[i];                outSide = cell.sides[cell.m_ArrivalWall];                if (i == cellPath.length-1) {                    testPtA = end;                    testPtB = end;                } else {                    testPtA = outSide.getPointA();                    testPtB = outSide.getPointB();                }                                if (!lastPtA.equals(testPtA)) {                    if (lastLineB.classifyPoint(testPtA, EPSILON) == PointClassification.RIGHT_SIDE) {                        //路点                        return new WayPoint(lastCell, lastPtB);                    } else {                        if (lastLineA.classifyPoint(testPtA, EPSILON) != PointClassification.LEFT_SIDE) {                            lastPtA = testPtA;                            lastCell = cell;                            //重设直线                            lastLineA.setPointB(lastPtA);                        }                    }                }                                if (!lastPtB.equals(testPtB)) {                    if (lastLineA.classifyPoint(testPtB, EPSILON) == PointClassification.LEFT_SIDE) {                        //路径点                        return new WayPoint(lastCell, lastPtA);                    } else {                        if (lastLineB.classifyPoint(testPtB, EPSILON) != PointClassification.RIGHT_SIDE) {                            lastPtB = testPtB;                            lastCell = cell;                            //重设直线                            lastLineB.setPointB(lastPtB);                        }                    }                }            }            return new WayPoint(cellPath[cellPath.length-1], end);    //终点        }
复制代码

 

标签: NAV导航网格寻路
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 16岁不认字怎么办 数学细节丢分怎么办 感觉自己老了怎么办 小学拼音不过关怎么办 小学面试不过关怎么办 小学阅读不过关怎么办 孩子计算老出错怎么办 工作中总是马虎怎么办 孩子总是计算错误怎么办 做设计老是犯错怎么办 小学生阅读总出错怎么办 写作文没思路怎么办 孩子不爱写作文怎么办 写作文没有素材怎么办 写作文没有灵感怎么办 做事工作马虎粗心大意怎么办 小孩作业马虎粗心大意怎么办 孩子写字一直错怎么办 孩子写字老错怎么办 写错字涂黑了怎么办 写错字不能涂改怎么办 孩子爱写错别字怎么办 孩子读题马虎怎么办 孩子知错不该怎么办 小孩胆小反应慢怎么办 孩孑经常流鼻血怎么办 中考考号写错了怎么办 头后仰就头晕怎么办 感觉自己要晕倒怎么办 孩子不愿动手写字怎么办 老年人恶心想吐怎么办 小学生老写错别字怎么办 突然头晕站不稳 怎么办 早上起床突然天旋地转怎么办 躺着突然感觉天旋地转怎么办 眩晕症发作时怎么办 低血糖恶心想吐怎么办 更年期头晕头胀怎么办 年轻人头晕头胀怎么办 教案:《眯眼了怎么办》 迷路了怎么办活动意图