首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是什么原因导致我的人工智能在地图上找到随机点而不选择真正的目标?

是什么原因导致我的人工智能在地图上找到随机点而不选择真正的目标?
EN

Stack Overflow用户
提问于 2017-02-17 00:12:58
回答 1查看 86关注 0票数 1

背景

我正在写一个基本的目标和移动人工智能。有两种类型的“生物”:活动fauna和非活动目标flora

问题

我的人工智能(附在fauna上)首先针对的是flora,但它只“看到”了一些flora。当AI看不到flora时,AI会绕圈旋转,似乎是随机的弹跳,即使还剩下flora

是什么导致只看到一些flora呢?为什么fauna在停止寻找flora之后似乎漫无目的地反弹呢?为什么在代码运行一段时间后,fauna就会聚集起来呢?是什么导致flora没有被看到?

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

我试图修复它

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

然后我意识到,生物旋转很可能无法与getAngle函数的返回相媲美。生物的旋转可能相当于回击角,但并不相等(例如。~= 720 but,但360 but=720 but)。在我修复这个问题之后,它似乎工作了一段时间,但是当我用更多的检查和更长的时间运行测试时,我发现了这些问题。

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

代码解释

该代码可在线访问:http://codepen.io/CKH4/pen/wgZqgL/

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

代码语言:javascript
运行
复制
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;
}

接下来,我有一些帮助函数来操作“生物”。

代码语言:javascript
运行
复制
// 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保留)。最后,只有在生物的对象中还剩下任何东西的情况下,代码才会将对象简化为最近的生物。如果在生物的对象中没有任何剩余的东西,它会返回一个未定义的数组。

代码语言:javascript
运行
复制
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个像素以内,该生物就会摧毁目标。否则,该生物转向一个积极的方向,“寻找”另一个目标。

代码语言:javascript
运行
复制
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。所有的生物都存储在一个动态的全局对象中。

代码语言:javascript
运行
复制
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中运行模拟,如果该生物有人工智能功能,它会调用它。问题也不在这里。

代码语言:javascript
运行
复制
let fixedUpdate = setInterval(function() {
  Object.keys(ob).forEach((ck) => {
    let c = ob[ck];

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

这是我用来显示它的代码。这只是基本的画布材料,所以问题肯定不在这里。

代码语言:javascript
运行
复制
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();

下面是嵌入的代码:

代码语言:javascript
运行
复制
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);
代码语言:javascript
运行
复制
body {
  margin: 0;
}
代码语言:javascript
运行
复制
<canvas height="1000" id="canvas" width="1000"></canvas>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-18 23:48:13

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

要修复它,我必须通过删除对对象的引用来存储ID。我改变了:

代码语言:javascript
运行
复制
first = of[Object.keys(of)[0]];

至:

代码语言:javascript
运行
复制
first = Object.keys(of)[0];

这在getTarget()的其余代码中造成了问题,因为我试图将属性附加到该生物的对象,而不是生物ID。

代码语言:javascript
运行
复制
}, [getDist(c.pos, first.pos), first]);

至:

代码语言:javascript
运行
复制
}, [getDist(c.pos, of[first].pos), first]);

这给了我完成的getTarget()

代码语言:javascript
运行
复制
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];
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42287146

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档