/* * @Author: gyw * @Date: 2019-09-09 * @Desc: A*寻路 * tilemap专用 */ export class AStarHelper { //其中的MAP.arr是二维数组 public static searchRoad(map: cc.TiledLayer, start_x: number, start_y: number, end_x: number, end_y: number, colliderTiles?: any[]) { if (start_x == end_x && start_y == end_y) return null; let layerSize = map.getLayerSize(); let rows = layerSize.width; //行 let cols = layerSize.height; //列 // let rows = PathMgr.getInstance().mapJson.length; //行 // let cols = PathMgr.getInstance().mapJson[0].length; //列 var openList = [], //开启列表 closeList = [], //关闭列表 result = [], //结果数组 result_index; //结果数组在开启列表中的序号 openList.push({ x: start_x, y: start_y, G: 0 });//把当前点加入到开启列表中,并且G是0 do { var currentPoint = openList.pop(); closeList.push(currentPoint); // if (Math.abs(currentPoint.x - start_x) > 10 || Math.abs(currentPoint.y - start_y) > 10) continue; var surroundPoint = this.SurroundPoint(currentPoint); for (var i in surroundPoint) { var item = surroundPoint[i]; //获得周围的八个点 if ( item.x >= 0 && //判断是否在地图上 item.y >= 0 && item.x < rows && item.y < cols && (this.checkCell(map, item.x, item.y) == 0 || this.checkCell(map, item.x, item.y) == 65) && //判断是否是障碍物 0代表是空位 this.existList(item, closeList) == -100 //判断是否在关闭列表中 && (!colliderTiles || !colliderTiles[item.x] || !colliderTiles[item.x][item.y]) ) { //g 到父节点的位置 //如果是上下左右位置的则g等于10,斜对角的就是14 var g = currentPoint.G + ((currentPoint.x - item.x) * (currentPoint.y - item.y) == 0 ? 10 : 14); if (this.existList(item, openList) == -100) { //如果不在开启列表中 //计算H,通过水平和垂直距离进行确定 item['H'] = Math.abs(end_x - item.x) * 10 + Math.abs(end_y - item.y) * 10; item['G'] = g; item['F'] = item['H'] + item['G']; item['parent'] = currentPoint; openList.push(item); } else { //存在在开启列表中,比较目前的g值和之前的g的大小 var index = this.existList(item, openList); //如果当前点的g更小 if (g < openList[index].G) { openList[index].parent = currentPoint; openList[index].G = g; openList[index].F = g + openList[index].H; } } } } //如果开启列表空了,没有通路,结果为空 if (openList.length == 0) { break; } openList.sort(this.sortF);//这一步是为了循环回去的时候,找出 F 值最小的, 将它从 "开启列表" 中移掉 } while ((result_index = this.existList({ x: end_x, y: end_y }, openList)) == -100); //判断结果列表是否为空 if (result_index == -100 || result_index == void 0) { result = []; } else { var currentObj = openList[result_index]; do { //把路劲节点添加到result当中 result.unshift({ x: currentObj.x, y: currentObj.y }); currentObj = currentObj.parent; } while (currentObj.x != start_x || currentObj.y != start_y); } return result; } //用F值对数组排序 private static sortF(a, b) { return b.F - a.F; } //获取周围八个点的值 public static SurroundPoint(curPoint) { var x = curPoint.x, y = curPoint.y; return [ { x: x - 1, y: y - 1 }, { x: x, y: y - 1 }, { x: x + 1, y: y - 1 }, { x: x + 1, y: y }, { x: x + 1, y: y + 1 }, { x: x, y: y + 1 }, { x: x - 1, y: y + 1 }, { x: x - 1, y: y } ] } //判断点是否存在在列表中,是的话返回的是序列号 private static existList(point, list) { for (var i in list) { if (point.x == list[i].x && point.y == list[i].y) { return i; } } return -100; } //检测单元格是否是障碍物 public static checkCell(mapLayer: cc.TiledLayer, x: number, y: number) { let res = mapLayer.getTileGIDAt(x, y); // let res = PathMgr.getInstance().mapJson[x][y]; return res; } }