Javascript 是什么导致我的AI在地图上找到随机点而不选择真实目标? 背景
我正在写一个具有基本目标和运动的AI。有两种类型的“生物”:活跃的Javascript 是什么导致我的AI在地图上找到随机点而不选择真实目标? 背景,javascript,debugging,artificial-intelligence,Javascript,Debugging,Artificial Intelligence,我正在写一个具有基本目标和运动的AI。有两种类型的“生物”:活跃的动物群,以及不活跃的目标植物群 问题 我的AI(附于动物群)首先针对植物群,但它只“看到”一些植物群。当人工智能看不到flora时,人工智能将旋转成圆圈,似乎随机反弹;即使还有flora残留 是什么原因导致只看到一些flora?为什么动物群在停止寻找植物群后似乎漫无目的地四处跳跃?为什么在代码运行一段时间后,fauna会结块?是什么原因导致看不到flora 如果你需要任何额外的信息,请询问 我试图修复它 我第一次尝试解决问题取得了
动物群
,以及不活跃的目标植物群
问题
我的AI(附于动物群
)首先针对植物群
,但它只“看到”一些植物群
。当人工智能看不到flora时,人工智能将旋转成圆圈,似乎随机反弹;即使还有flora
残留
是什么原因导致只看到一些flora
?为什么动物群
在停止寻找植物群
后似乎漫无目的地四处跳跃?为什么在代码运行一段时间后,fauna
会结块?是什么原因导致看不到flora
如果你需要任何额外的信息,请询问
我试图修复它
我第一次尝试解决问题取得了一些成功,但没有完全解决问题。这就是我使用对象而不是数组重写代码的时候。一旦我这么做了,目标就成功了,但一些动物群会没完没了地旋转
然后我意识到,生物的旋转很可能无法与getAngle函数的返回进行比较。该生物的旋转可能等同于getAngle的返回,但不会相等(例如360度~=720度,但360度!=720度)。在我修复了这个问题之后,它似乎工作了一段时间,但是当我通过更多的检查和更长的时间运行测试时,我发现了这些问题
我真的不确定什么会导致这样的问题,但我很想知道。谢谢你的帮助。:)
代码解释
该代码可在线访问:
在我的代码开始时,我有一些对象
原型扩展,允许我使用数组之类的对象。它们大致相当于它们的数组
对应项。我不认为这些是问题的根源,但它们是程序运行所必需的
Object.prototype.filter = function(fn) {
let ob = this, keep = {},
k = Object.keys(ob);
for (let i = 0; i < k.length; i++) {
if (fn(k[i], ob[k[i]]))
keep[k[i]] = ob[k[i]];
}
return keep;
}
Object.prototype.forEach = function(fn) {
let ob = this, k = Object.keys(ob);
for (let i = 0; i < k.length; i++)
fn(k[i], ob[k[i]]);
}
Object.prototype.reduce = function(test, initialValue = null) {
let ob = this, k = Object.keys(ob),
accumulator = initialValue || ob[k[0]],
i = (initialValue === null) ? 1 : 0;
for (; i < k.length; i++)
accumulator = test(accumulator, k[i], ob[k[i]], ob);
return accumulator;
}
现在我有了目标函数。它首先获取运行ai的生物,然后获取该生物的一个对象进行查看,然后采用当前只能找到最近的模式,最后采用过滤功能,让目标查找者只能查看flora
代码首先过滤掉那些不在人工智能视线内的。这就是我所期望的问题所在。接下来,它应用输入过滤器(这样在我的情况下,只有flora
保留)。最后,只有当生物对象中还有剩余的生物时,代码才会将该对象减少到最近的生物。如果在生物的对象中没有任何剩余,它将返回一个未定义的数组
function getTarget(c, of, mode = `nearest`, filter) {
let first;
// filter so its only the ones in view
of = of.filter((k, t) => {
return Math.abs(getAngle(c.pos, t.pos) - c.direction) < c.viewAngle / 2;
});
// filter for target type; eg. only return flora
if (filter)
of = of.filter(filter);
if (Object.keys(of).length) {
first = of[Object.keys(of)[0]];
if (mode == `nearest`) {
return of.reduce((acc, k, cur) => {
let dist = getDist(c.pos, cur.pos);
if (dist < acc[0])
return [dist, k];
else
return acc;
}, [getDist(c.pos, first.pos), first]);
}
}
else
return [undefined, undefined];
}
在这里,我生成了一个对象,其中包含随机放置的flora
和flora
。我使用的ID系统使用的是对象
,而不是和数组
。所有生物都存储在动态全局对象中
ob = {};
for (let i = 20; i > 0; i--) {
let id = Math.floor(Math.random() * 1000000000),
type = (Math.random() > .2 ? `flora` : `fauna`);
ob[id] = {
type: type,
pos: { x: Math.floor(Math.random() * canvas.width), y: Math.floor(Math.random() * canvas.height) },
direction: Math.random() * 360
}
if (type == `fauna`) {
ob[id].ai = findfood;
ob[id].viewAngle = 90;
ob[id].speed = .8;
ob[id].turnSpeed = 1.6;
}
}
然后,我在setInterval中运行模拟,如果生物拥有AI函数,它将调用AI函数。问题也不在这里
let fixedUpdate = setInterval(function() {
Object.keys(ob).forEach((ck) => {
let c = ob[ck];
if (c && c.ai)
c.ai.apply(c);
});
}, 1000 / 60);
这是我用来显示它的代码。这只是基本的画布材料,所以问题肯定不在这里
let draw = () => {
// clear canvas
ctx.putImageData(emptyCanvas, 0, 0);
Object.keys(ob).forEach((ck) => {
let c = ob[ck];
if (c.type == 'flora')
ctx.fillStyle = '#22cc33';
else if (c.type == 'fauna') {
ctx.fillStyle = '#0066ee';
ctx.beginPath();
ctx.moveTo(c.pos.x, c.pos.y);
// ctx.lineTo(c.pos.x + 100, c.pos.y - 50);
// ctx.lineTo(c.pos.x + 100, c.pos.y + 50);
ctx.lineTo(c.pos.x, c.pos.y);
ctx.fill();
ctx.beginPath();
ctx.arc(c.pos.x, c.pos.y, 100, (c.direction - c.viewAngle / 2) * Math.PI / 180, (c.direction + c.viewAngle / 2) * Math.PI / 180);
ctx.fill();
}
else
ctx.fillStyle = '#424242';
ctx.beginPath();
ctx.arc(c.pos.x, c.pos.y, 10, 0, 2 * Math.PI);
ctx.fill();
});
requestAnimationFrame(draw);
}
draw();
以下是嵌入的代码:
console.clear();
Object.prototype.filter=函数(fn){
让ob=this,keep={},
k=对象键(ob);
for(设i=0;i{
返回数学abs(getAngle(c.pos,t.pos)-c.direction){
设dist=getDist(c.pos,cur.pos);
如果(距离c.type==`flora`);
this.target=目标[1];
if(ob[this.target]){
调用(this,getAngle(this.pos,ob[this.target].pos));
if(getDist(this.pos,ob[this.target].pos)>5)
移动,呼叫(这个);
否则{
删除ob[this.target];
}
}
其他的
旋转呼叫(这个,这个,旋转速度);
}
ob={};
对于(设i=20;i>0;i--){
设id=Math.floor(Math.random()*100000000),
type=(Math.random()>.2?`flora`:`fauna`);
ob[id]={
let fixedUpdate = setInterval(function() {
Object.keys(ob).forEach((ck) => {
let c = ob[ck];
if (c && c.ai)
c.ai.apply(c);
});
}, 1000 / 60);
let draw = () => {
// clear canvas
ctx.putImageData(emptyCanvas, 0, 0);
Object.keys(ob).forEach((ck) => {
let c = ob[ck];
if (c.type == 'flora')
ctx.fillStyle = '#22cc33';
else if (c.type == 'fauna') {
ctx.fillStyle = '#0066ee';
ctx.beginPath();
ctx.moveTo(c.pos.x, c.pos.y);
// ctx.lineTo(c.pos.x + 100, c.pos.y - 50);
// ctx.lineTo(c.pos.x + 100, c.pos.y + 50);
ctx.lineTo(c.pos.x, c.pos.y);
ctx.fill();
ctx.beginPath();
ctx.arc(c.pos.x, c.pos.y, 100, (c.direction - c.viewAngle / 2) * Math.PI / 180, (c.direction + c.viewAngle / 2) * Math.PI / 180);
ctx.fill();
}
else
ctx.fillStyle = '#424242';
ctx.beginPath();
ctx.arc(c.pos.x, c.pos.y, 10, 0, 2 * Math.PI);
ctx.fill();
});
requestAnimationFrame(draw);
}
draw();
first = of[Object.keys(of)[0]];
first = Object.keys(of)[0];
}, [getDist(c.pos, first.pos), first]);
}, [getDist(c.pos, of[first].pos), first]);
function getTarget(c, of, mode = `nearest`, filter) {
let first;
// filter so its only the ones in view
of = of.filter((k, t) => {
return Math.abs(getAngle(c.pos, t.pos) - c.direction) < c.viewAngle / 2;
});
// filter for target type; eg. only return flora
if (filter)
of = of.filter(filter);
if (Object.keys(of).length) {
first = Object.keys(of)[0];
if (mode == `nearest`) {
return of.reduce((acc, k, cur) => {
let dist = getDist(c.pos, cur.pos);
if (dist < acc[0])
return [dist, k];
else
return acc;
}, [getDist(c.pos, of[first].pos), first]);
}
}
else
return [undefined, undefined];
}