gpt4 book ai didi

javascript - 是什么导致我的 AI 在 map 上找到随机点而不选择真正的目标?

转载 作者:行者123 更新时间:2023-11-28 04:59:14 25 4
gpt4 key购买 nike

背景

我正在编写一个具有基本目标和运动的 AI。有两种“生物”:活跃的fauna ,以及非事件目标 flora .

问题

我的 AI(附加到 fauna )首先针对 flora但它只“看到”了一些 flora .当没有flora对 AI 可见,AI 会绕圈旋转并看似随机弹跳;即使有flora其余的。

是什么导致了 flora 中的一部分被看见?为什么fauna在他们停止寻找 flora 后,似乎漫无目的的蹦蹦跳跳?为什么fauna代码运行一段时间后聚集起来?是什么导致 flora不被看见?

如果您需要任何额外的信息,请询问。

我尝试修复它

我第一次尝试解决这个问题取得了一些成功,但并没有完全解决这个问题。这是我使用对象而不是数组重写代码的时候。一旦我这样做了,目标就起作用了,但是有些 fauna会无休止地旋转。

然后我意识到,生物旋转很可能与 getAngle 函数的返回无法比较。生物的旋转可能等同于 getAngle 的返回但不相等(例如 360deg ~= 720deg 但 360deg != 720deg)。在我修复此问题后,它似乎工作了一段时间,但当我通过更多检查和更长的时间运行测试时,我发现了这些问题。

我真的不确定什么会导致这样的问题,但我很想知道。感谢您的帮助 :)

代码说明

代码可在线获取:http://codepen.io/CKH4/pen/wgZqgL/

在我的代码开头我有一些 Object允许我使用像数组这样的对象的原型(prototype)扩展。这些大致相当于它们的Array同行。我不相信这些是问题的根源,但它们是程序运行所必需的。

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;
}

接下来我有一些辅助函数来操作“生物”。
// calculates the distance between two creatures by taking their [pos] as inputs
function getDist(p1, p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
// calculates the angle from point1 to point2
function getAngle(p1, p2) {
return (Math.atan2(p2.y - p1.y, p2.x - p1.x) / Math.PI * 180 + 360) % 360;
}

// moves the creature in the direction they are facing
function move() {
this.pos.x += this.speed * Math.cos(this.direction * Math.PI / 180);
this.pos.y += this.speed * Math.sin(this.direction * Math.PI / 180);
}
// rotates the creature towards the angle input by the turn speed of the creature
function rotateTowards(angle) {
this.direction += Math.sign(angle - this.direction) * this.turnSpeed;
this.direction = this.direction % 360;
}
// rotates the creature by the angle provided
function rotateBy(angle) {
this.direction += angle;
this.direction = this.direction % 360;
}

现在我有了定位功能。它首先获取正在运行 ai 的生物,然后它需要一个生物的对象来查看,接下来它采用目前只能找到最近的模式,最后它采用过滤功能,让目标查找器只看植物群。

代码首先过滤掉那些不在 AI 视线范围内的代码。这就是我预期的问题所在。接下来它应用输入过滤器(所以在我的例子中只剩下 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];
}

最后,我有了将目标系统与运动代码联系在一起的通用 AI。如果有目标,该生物会转身朝目标移动。如果目标在生物 5 像素范围内,则生物会摧毁目标。否则,该生物会转向正方向,“寻找”另一个目标。
function findfood() {
let target = getTarget(this, ob, `nearest`, (k, c) => c.type == `flora`);

this.target = target[1];

if (ob[this.target]) {
rotateTowards.call(this, getAngle(this.pos, ob[this.target].pos));
if (getDist(this.pos, ob[this.target].pos) > 5)
move.call(this);
else {
delete ob[this.target];
}
}
else
rotateBy.call(this, this.turnSpeed);
}

这里我生成一个随机放置的对象 florafauna .我使用 ID 系统,使用 Object而不是和 Array .所有的生物都存储在一个动态的全局对象中。
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 函数。问题也不在这里。
let fixedUpdate = setInterval(function() {
Object.keys(ob).forEach((ck) => {
let c = ob[ck];

if (c && c.ai)
c.ai.apply(c);
});
}, 1000 / 60);

这是我用来显示它的代码。它只是基本的 Canvas 东西,所以问题肯定不在这里。
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 = 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;
}



function getDist(p1, p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
function getAngle(p1, p2) {
return (Math.atan2(p2.y - p1.y, p2.x - p1.x) / Math.PI * 180 + 360) % 360;
}

function move() {
this.pos.x += this.speed * Math.cos(this.direction * Math.PI / 180);
this.pos.y += this.speed * Math.sin(this.direction * Math.PI / 180);
}
function rotateTowards(angle) {
this.direction += Math.sign(angle - this.direction) * this.turnSpeed;
this.direction = this.direction % 360;
}
function rotateBy(angle) {
this.direction += angle;
this.direction = this.direction % 360;
}

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];
}

function findfood() {

let target = getTarget(this, ob, `nearest`, (k, c) => c.type == `flora`);

this.target = target[1];

if (ob[this.target]) {
rotateTowards.call(this, getAngle(this.pos, ob[this.target].pos));
if (getDist(this.pos, ob[this.target].pos) > 5)
move.call(this);
else {
delete ob[this.target];
}
}
else
rotateBy.call(this, this.turnSpeed);

}




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;
}
}

console.log(ob);



let ctx = canvas.getContext(`2d`);
let emptyCanvas = ctx.getImageData(0,0,canvas.width,canvas.height);

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();



let fixedUpdate = setInterval(function() {
Object.keys(ob).forEach((ck) => {
let c = ob[ck];

if (c && c.ai)
c.ai.apply(c);
})
}, 1000 / 60);
body {
margin: 0;
}
<canvas height="1000" id="canvas" width="1000"></canvas>

最佳答案

我在我的代码中发现了错误。我在getTarget() ,当我获得第一个可能的目标( of[0] )时,我首先将其存储为对生物的引用,而不是生物的 ID。

为了解决这个问题,我不得不通过删除对对象的引用来存储 ID。我变了:

first = of[Object.keys(of)[0]];

到:
first = Object.keys(of)[0];

这导致 getTarget() 的其余代码出现问题。因为我试图获取附加到生物对象的属性,而不是生物 ID。我通过改变来解决这个问题:
}, [getDist(c.pos, first.pos), first]);

到:
}, [getDist(c.pos, of[first].pos), first]);

这给了我完成的 getTarget()的:
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];
}

关于javascript - 是什么导致我的 AI 在 map 上找到随机点而不选择真正的目标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42287146/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com