是什么导致我的 AI 在没有选择真实目标的情况下在地图上找到随机点?
What causes my AI to find random points on the map without picking a real target?
背景
我正在编写一个具有基本定位和移动功能的 AI。 "creatures" 有两种类型:活动的 fauna
和非活动的目标 flora
.
问题
我的 AI(附加到 fauna
)首先瞄准 flora
,但它只 "sees" 一些 flora
。当 AI 看不到 flora
时,AI 会原地转圈,看似 运行domly 弹跳;即使还有 flora
剩余。
什么导致只能看到 flora
中的一部分?为什么 fauna
在找不到 flora
之后似乎漫无目的地四处乱跳?为什么 fauna
在代码 运行 一段时间后会聚集起来?是什么原因导致 flora
看不到?
如果您需要任何额外信息,请询问。
我尝试修复它
我第一次尝试解决这个问题取得了一些成功,但没有完全解决问题。这是我使用对象而不是数组重写代码的时候。一旦我这样做了,目标就起作用了,但是一些 fauna
会无休止地旋转。
然后我意识到生物的旋转很可能无法与 getAngle 函数的 return 相提并论。生物的旋转可能等同于 getAngle 的 return 但不会相等(例如 360deg ~= 720deg 但 360deg != 720deg)。修复此问题后,它似乎可以工作一段时间,但当我 运行 进行更多检查和更长时间的测试时,我发现了这些问题。
我真的不确定是什么会导致这样的问题,但我很想知道。感谢您的帮助 :)
代码说明
代码可在线获取:http://codepen.io/CKH4/pen/wgZqgL/
在我的代码开头,我有一些 Object
原型扩展,允许我使用数组等对象。这些大致相当于他们的 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;
}
接下来我有一些辅助函数来操作 "creatures"。
// 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
)。最后,只有当生物对象中还有剩余时,代码才会将对象缩减为最近的生物。如果 creatures 的对象中没有任何剩余,则它 return 是一个未定义的数组。
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 像素范围内,则该生物会摧毁目标。否则该生物转向正方向,"looking" 另一个目标。
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);
}
这里我生成了一个对象,其中 运行domly 放置了 flora
和 fauna
。我使用的 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]
) 时,我将 first 存储为对生物的引用而不是生物的 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];
}
背景
我正在编写一个具有基本定位和移动功能的 AI。 "creatures" 有两种类型:活动的 fauna
和非活动的目标 flora
.
问题
我的 AI(附加到 fauna
)首先瞄准 flora
,但它只 "sees" 一些 flora
。当 AI 看不到 flora
时,AI 会原地转圈,看似 运行domly 弹跳;即使还有 flora
剩余。
什么导致只能看到 flora
中的一部分?为什么 fauna
在找不到 flora
之后似乎漫无目的地四处乱跳?为什么 fauna
在代码 运行 一段时间后会聚集起来?是什么原因导致 flora
看不到?
如果您需要任何额外信息,请询问。
我尝试修复它
我第一次尝试解决这个问题取得了一些成功,但没有完全解决问题。这是我使用对象而不是数组重写代码的时候。一旦我这样做了,目标就起作用了,但是一些 fauna
会无休止地旋转。
然后我意识到生物的旋转很可能无法与 getAngle 函数的 return 相提并论。生物的旋转可能等同于 getAngle 的 return 但不会相等(例如 360deg ~= 720deg 但 360deg != 720deg)。修复此问题后,它似乎可以工作一段时间,但当我 运行 进行更多检查和更长时间的测试时,我发现了这些问题。
我真的不确定是什么会导致这样的问题,但我很想知道。感谢您的帮助 :)
代码说明
代码可在线获取:http://codepen.io/CKH4/pen/wgZqgL/
在我的代码开头,我有一些 Object
原型扩展,允许我使用数组等对象。这些大致相当于他们的 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;
}
接下来我有一些辅助函数来操作 "creatures"。
// 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
)。最后,只有当生物对象中还有剩余时,代码才会将对象缩减为最近的生物。如果 creatures 的对象中没有任何剩余,则它 return 是一个未定义的数组。
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 像素范围内,则该生物会摧毁目标。否则该生物转向正方向,"looking" 另一个目标。
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);
}
这里我生成了一个对象,其中 运行domly 放置了 flora
和 fauna
。我使用的 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]
) 时,我将 first 存储为对生物的引用而不是生物的 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];
}