당신이 이해할 수 있도록 분석을 자세히 폭도에 대한 일련의 기사에.
텍스트
첫째, 맨하탄 평가 방법.
추가 및 기간의 직선 거리 또는 행에서 몇 단락으로 이해 할 수 있습니다.
// 曼哈顿估价法,传入当前点与目标点,返回估值
// abs 为取绝对值
manHattan (nowPoint, pIndex) {
let dx = Math.abs(nowPoint.x - pIndex.x);
let dy = Math.abs(nowPoint.y - pIndex.y);
return dx + dy;
}
그리고 우리가 정보를 가지고 있어야 경로에있는 목표 지점을 분석 할 수 있습니다.
// new 一个空对象
let obj = new Object();
// 每个网格的点的行和列 对应 x 和 y
obj.x = v.x;
obj.y = v.y;
obj.g = this.manHattan(v, this.mIndex);
obj.h = this.manHattan(v, this.pIndex);
// g 为从起点,沿着路径,移动到当前点的移动耗费。
// h 为从当前点到终点的移动耗费。这不包括障碍,单纯的是曼哈顿距离,也就是直线距离。因为我们不知道什么时候有障碍,这叫启发式。
// 我们的路径是通过反复遍历 open 列表并且选择具有最低 f 值装入 close 列表。因为 f 是综合值,调整 g 和 h 的比例会起到不同寻路效果。
obj.f = obj.g + obj.h;
// 起点无上级,然后搜索到目标点后可以轻易的靠着 parent 回溯到起点。
obj.parent = parent;
단계별 데모
데이터는 성명에서 시작합니다.
start () {
// 小怪的坐标,起点
this.mIndex = cc.v2(4, 0);
// 玩家坐标点,终点
this.pIndex = cc.v2(3, 9);
// 开始
this.aStar();
},
제한 (500)는 물론, 그래서 당신이 붙어 일으키는 것을 방지하기 위해 경로를 찾을 수 없습니다으로 .. 각 사이클을 이해된다.
그리고 우리가 출발점으로 객체를 생성 할 수 있습니다. 그리고 가까운리스트에 배치.
이러한 점 가득 확대리스트 닫기, 검색의 완료에 열기의 하부 F 점 목록을 선택한 다음 선택하는 점에리스트를 열고, 검색되었다. 우리는 결승선을 찾을 때까지.
aStar () {
// 限制次数 500;
// 首先将小怪的位置装入 close 列表
let time = 500;
let obj = new Object();
obj.x = this.mIndex.x;
obj.y = this.mIndex.y;
obj.g = this.manHattan(this.mIndex, this.mIndex);
obj.h = this.manHattan(this.mIndex, this.pIndex);
obj.f = obj.g + obj.h;
obj.parent = null;
// 将起点放入
this.pushInClose(obj);
// ......
}
pushInClose (obj) {
this.close.push(obj);
},
같이
원의 현재 위치 둘러보고, 처음부터 우리를 한 다음 F 성장 호르몬 GET의 값을 계산합니다.
while (true) {
time--;
// 周围一圈装入 open
this.aroundPos(temp);
// 在 open 中找到 f 最小的,装入 close 并返回该点;
temp = this.findMinInOpen();
if (temp.x == this.pIndex.x && temp.y == this.pIndex.y) {
// 到达目的地
break;
}
if (time <= 0) {
console.log('寻找不到');
break;
}
}
주변에 보면
aroundPos (parent) {
// 上下左右四个方向
let dir = [[0,1],[1,0],[0,-1],[-1,0]];
for (let i = 0; i < 4;i++) {
let mx = parent.x + dir[i][0];
let my = parent.y + dir[i][1];
// 是否出界
if (mx < 0 || mx > 6 || my < 0 || my > 9) {
continue;
}
// 是否为墙
if (this.map[mx][my] == 1) {
continue;
}
// 是否已经在 close 中了
if (this.isInClose(mx, my)) {
continue;
}
// 是否已经在 close 中了
if (this.isInOpen(mx, my)) {
continue;
}
// 装入 open
this.pushInOpen(cc.v2(mx, my), parent);
}
},
findMinInOpen () {
let min = 999;
let index = null;
// 找到 open 中最小的 f 的点的下标
for (let i = 0; i < this.open.length; i++) {
if (this.open[i].f <= min) {
min = this.open[i].f;
index = i;
}
}
// 运用 splice 将 f 最小的点切出来
let obj = this.open.splice(index, 1);
// 放入 close 列表并返回
this.pushInClose(obj[0]);
return obj[0];
},
이 새로운 점 때문에 방법은 가까운 배열에 직접 가까운 목록을 배치, 우리는 오픈 정보 점의 목록을 작성해야합니다.
pushInOpen (v, parent) {
let obj = new Object();
obj.x = v.x;
obj.y = v.y;
obj.g = this.manHattan(v, this.mIndex);
obj.h = this.manHattan(v, this.pIndex);
obj.f = obj.g + obj.h;
obj.parent = parent;
this.open.push(obj);
},
루프 개폐 여부 개의 목록을 결정
isInOpen (mx, my) {
for (let i = 0; i < this.open.length; i++) {
if (this.open[i].x == mx && this.open[i].y == my) {
return true;
}
}
return false;
},
isInClose (mx, my) {
for (let i = 0; i < this.close.length; i++) {
if (this.close[i].x == mx && this.close[i].y == my) {
return true;
}
}
return false;
},
마지막으로, 우리는 것을 발견
가까운 지점 목록의 많은이 발견에, 배열이 최종 목적지 지점해야합니다.
최종 목표 지점 가까이 배열입니다, 우리는 단지 목표 지점에 따라, 연속 상승 액세스 부모 다시 시작점으로 갈 수 있습니다.
코드 구현
// 根据 parent 最终确认路线
let l = this.close.length - 1;
let p = this.close[l];
this.final = [];
while(p) {
this.final.push(p);
p = p.parent;
}
// 将 close 中的正确路线装入 final 后其实是反序的
// 翻转
this.final.reverse();
// 沿着 final 走
this.go(0);
경로를 따라 산책은 매우 간단, runAction가 마무리 될 때까지 이동을 계속 사용
go (i) {
this.me.runAction(cc.sequence(
cc.moveTo(0.5,this.convertToPoints(this.final[i].x, this.final[i].y)),
cc.callFunc(() => {
if (i == this.final.length - 1) return;
i++;
this.go(i);
},this)
));
},
행 및 열 좌표와 실제 좌표에
// 转化坐标
convertToPoints (dx, dy) {
let y = 300 - 100 * dx;
let x = 100 * dy - 450;
return cc.v2(x, y);
},
글쎄, 난 작은 친구가이 시간을 이해하지 모르겠어요!
O (∩_∩) O ~~