xy-server/game/core/PathUtil.ts

294 lines
11 KiB
TypeScript
Raw Permalink Normal View History

2025-04-23 09:34:08 +08:00
import SKDataUtil from "../gear/SKDataUtil";
export default class PathUtil {
static getAvailabelPoint(r: number, l: number, mapArr: any[], rows: number, lines: number): any {
if (r < 0) {
r = 0;
}
if (l < 0) {
l = 0;
}
if (r >= rows) {
r = rows - 1;
}
if (l >= lines) {
l = lines - 1;
}
let value = SKDataUtil.intOf2Array(mapArr, r, l, 0);
if (value != 0) {
return {
r: r,
l: l
};
}
let count = 1;
for (let i = 0; i < 10000000; i++) {
if (count > lines && count > rows) {
return {
r: -1,
l: -1
};
}
if (r + count < rows && mapArr[r + count][l] != 0) {
return {
r: r + count,
l: l
};
}
if (l + count < lines && mapArr[r][l + count] != 0) {
return {
r: r,
l: l + count
};
}
if (r >= count && mapArr[r - count][l] != 0) {
return {
r: r - count,
l: l
};
}
if (l >= count && mapArr[r][l - count] != 0) {
return {
r: r,
l: l - count
};
}
if (r + count < rows && l + count < lines && mapArr[r + count][l + count] != 0) {
return {
r: r + count,
l: l + count
};
}
if (r >= count && l >= count && mapArr[r - count][l - count] != 0) {
return {
r: r - count,
l: l - count
};
}
if (r >= count && l + count < lines && mapArr[r - count][l + count] != 0) {
return {
r: r - count,
l: l + count
};
}
if (l >= count && r + count < rows && mapArr[r + count][l - count] != 0) {
return {
r: r + count,
l: l - count
};
}
count++;
}
};
// 寻路
static searchRoad(start_r: number, start_l: number, end_r: number, end_l: number, mapArr: any[], rows: number, cols: number): any[] {
if (end_r == -1 && end_l == -1) {
return [];
}
let openList: any[] = [], //开启列表
closeObjList: any = {}, //关闭列表索引
openObjList: any = {}, //开启列表索引
result: any[] = [], //结果数组
result_index: number = 0; //终点位置
if (start_r == end_r && start_l == end_l) {
return result;
}
openList.push({
r: start_r,
l: start_l,
G: 0
}); //把当前点加入到开启列表中并且G是0
openObjList[start_r * cols + start_l] = start_r * cols + start_l;
do {
var currentPoint = openList[0];
if (openList.length > 1) {
openList[0] = openList[openList.length - 1];
this.minheap_filterdown(openList, 0, openObjList, cols);
}
openList.splice(openList.length - 1, 1);
closeObjList[currentPoint.r * cols + currentPoint.l] = currentPoint;
delete openObjList[currentPoint.r * cols + currentPoint.l];
let surroundPoint = this.SurroundPoint(currentPoint);
for (let i in surroundPoint) {
let item: any = surroundPoint[i]; //获得周围的八个点
if (
item.r >= 0 && //判断是否在地图上
item.l >= 0 &&
item.r < rows &&
item.l < cols &&
mapArr[item.r][item.l] != 0 && //判断是否是障碍物
!this.existInCloseList(item, closeObjList, cols) && //判断是否在关闭列表中
mapArr[item.r][currentPoint.l] != 0 && //判断之间是否有障碍物,如果有障碍物是过不去的
mapArr[currentPoint.r][item.l] != 0) {
//g 到父节点的位置
//如果是上下左右位置的则g等于10斜对角的就是14
var g = currentPoint.G + ((currentPoint.r - item.r) * (currentPoint.l - item.l) == 0 ? 10 : 14);
let temp: number = this.existInOpenList(item, openObjList, cols);
if (temp == null) { //如果不在开启列表中
//计算H通过水平和垂直距离进行确定
item['H'] = Math.abs(end_r - item.r) * 10 + Math.abs(end_l - item.l) * 10;
item['G'] = g;
item['F'] = item.H + item.G;
item['parent'] = currentPoint;
openList.push(item);
openObjList[item.r * cols + item.l] = openList.length - 1;
if (item['H'] == 0) {
break;
}
this.minheap_filterup(openList, openList.length - 1, openObjList, cols);
} else { //存在在开启列表中比较目前的g值和之前的g的大小
let index: number = temp;
//如果当前点的g更小
if (g < openList[index].G) {
openList[index].parent = currentPoint;
openList[index].G = g;
openList[index].F = g + openList[index].H;
}
this.minheap_filterup(openList, index, openObjList, cols);
}
}
}
//如果开启列表空了,没有通路,结果为空
if (openList.length == 0) {
break;
}
// openList.sort(this.sortF);//这一步是为了循环回去的时候,找出 F 值最小的, 将它从 "开启列表" 中移掉
} while (!(result_index = this.existInOpenList({
r: end_r,
l: end_l
}, openObjList, cols)));
//判断结果列表是否为空
if (!result_index) {
result = [];
} else {
var currentObj = openList[result_index];
do {
//把路劲节点添加到result当中
result.unshift({
r: currentObj.r,
l: currentObj.l
});
currentObj = currentObj.parent;
} while (currentObj.r != start_r || currentObj.l != start_l);
}
let alpha = 0.8;
let beta = 0.2;
let p = result.slice(0);
for (let i = 1; i <= 8; i++) {
for (let k = 2; k < p.length - 1; k++) {
let t = p[k];
let l = p[k - 1];
let n = p[k + 1];
t.l = t.l + alpha * (result[k].l - t.l) + beta * (l.l - 2 * t.l + n.l);
t.r = t.r + alpha * (result[k].r - t.r) + beta * (l.r - 2 * t.r + n.r);
}
}
return p;
// return result;
};
/**
*
* list
* pos
* indexlist list中的位置
* cols
*/
static minheap_filterup(list: any[], pos: number, indexlist: any, cols: number) {
let c = pos; // 当前节点(current)的位置
let p = Math.floor((c - 1) / 2); // 父(parent)结点的位置
let tmp = list[c]; // 当前节点(current)
while (c > 0) { // c>0 还未上升到顶部
if (list[p].F <= tmp.F) // 父节点比当前节点小,上升结束
break;
else {
list[c] = list[p]; // 父节点放到当前位置
indexlist[list[p].r * cols + list[p].l] = c; //设置父节点的索引位置
c = p; // 当前位置上升到父节点位置
p = Math.floor((p - 1) / 2); // 重新计算父节点位置
}
}
list[c] = tmp; // 把传入节点放到上升位置
indexlist[tmp.r * cols + tmp.l] = c; // 设置传入点的索引位置
};
/**
*
* list
* pos
* indexlist list中的位置
* cols
*/
static minheap_filterdown(list: any[], pos: number, indexlist: any, cols: number) {
let c = pos; // 当前(current)节点的位置
let l = 2 * c + 1; // 左(left)孩子的位置
let tmp = list[c]; // 当前(current)节点
let end = list.length - 1; // 数组终点
while (l <= end) {
if (l < end && list[l].F > list[l + 1].F) // "l"是左孩子,"l+1"是右孩子
l++; // 左右两孩子中选择较小者即list[l+1]
if (tmp.F <= list[l].F) // 当前节点比最小的子节点小,调整结束
break;
else {
list[c] = list[l];
indexlist[list[l].r * cols + list[l].l] = c;
c = l;
l = 2 * l + 1;
}
}
list[c] = tmp;
indexlist[tmp.r * cols + tmp.l] = c;
};
// 是否在开放列表中
static existInOpenList(point: any, list: any, cols: number): number {
let result: number = list[point.r * cols + point.l];
return result;
};
//获取周围八个点的值
static SurroundPoint(curPoint: any): any[] {
let r = curPoint.r,
l = curPoint.l;
return [{
r: r - 1,
l: l - 1
},
{
r: r,
l: l - 1
},
{
r: r + 1,
l: l - 1
},
{
r: r + 1,
l: l
},
{
r: r + 1,
l: l + 1
},
{
r: r,
l: l + 1
},
{
r: r - 1,
l: l + 1
},
{
r: r - 1,
l: l
}
];
};
// 是否在关闭列表中
static existInCloseList(point: any, list: any, cols: number): boolean {
if (list[point.r * cols + point.l]) {
return true;
}
return false;
};
}