引擎版本 v2.0.10
小怪的思考
在上一篇文章中,小怪采用了包围盒子边界检测的方法实现了寻路。但是狡猾的玩家对此采取了措施。他偷偷的加固了防线!
这可难坏了小怪。
哼,玩家一定是想消耗我的体力,让我像无头苍蝇般乱走,我才不上当呢!
于是我拿出了 KUOKUO 大人赏的纸和笔,开始思考!
我需要两个列表(数组):
一个记录下所有被考虑来寻找最近的点集合
一个记录下不会再被考虑的点集合
// 一个点上应该具有的属性
let obj = new Object();
obj.x = ...
obj.y = ...
// g 随着离开始点越来越远而增大
obj.g = ...
// h 当前点到目标点的移动量估算值
obj.h = ...
obj.f = ...
obj.parent = ...
根据 f 值寻路后可依靠 parent 回溯
// ......
this.final = [];
while(p) {
this.final.push(p);
p = p.parent;
}
// 翻转
this.final.reverse();
// 沿着 final 走
// ......
这样虽然多思考了几个路径上的点,但是我思考后可直接行走。
试试?试试!
哼哼!愚蠢的人类。
完整代码
cc.Class({
extends: cc.Component,
properties: {
// 小怪
me : cc.Node
},
onLoad () {
// 地图数据,0是地板,1是墙
this.map = [
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
];
this.open = [];
this.close = [];
},
start () {
// 小怪的坐标
this.mIndex = cc.v2(4, 0);
// 玩家坐标点
this.pIndex = cc.v2(3, 9);
// 开始
this.aStar();
},
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);
let temp = obj;
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;
}
}
// 根据 parent 最终确认路线
let l = this.close.length - 1;
let p = this.close[l];
this.final = [];
while(p) {
this.final.push(p);
p = p.parent;
}
// 翻转
this.final.reverse();
// 沿着 final 走
this.go(0);
},
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)
));
},
findMinInOpen () {
let min = 999;
let index = null;
for (let i = 0; i < this.open.length; i++) {
if (this.open[i].f <= min) {
min = this.open[i].f;
index = i;
}
}
let obj = this.open.splice(index, 1);
this.pushInClose(obj[0]);
return obj[0];
},
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;
}
// 是否已经在 open 中了
if (this.isInOpen(mx, my)) {
continue;
}
// 装入 open
this.pushInOpen(cc.v2(mx, my), parent);
}
},
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;
},
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);
},
pushInClose (obj) {
this.close.push(obj);
},
// 转化坐标
convertToPoints (dx, dy) {
let y = 300 - 100 * dx;
let x = 100 * dy - 450;
return cc.v2(x, y);
},
// 曼哈顿估价法,传入当前点与目标点,返回估值
manHattan (nowPoint, pIndex) {
let dx = Math.abs(nowPoint.x - pIndex.x);
let dy = Math.abs(nowPoint.y - pIndex.y);
return dx + dy;
}
});
O(∩_∩)O~~