【问题标题】:struggling to create a smooth-moving snake in p5 js - tail catching up to head努力在 p5 js 中创建一条平滑移动的蛇 - 尾巴追上头部
【发布时间】:2021-10-10 23:37:30
【问题描述】:

我正在制作一个 p5 草图,其中包含在屏幕上随机移动的小蛇。

不幸的是,每次急转弯时,尾巴都会追上头部。

这是我用来计算移动的函数,我尝试了几种不同的方法来计算速度,固定数字,相对于蛇的长度。

它应该通过以半随机方向移动蛇头(点 [3])然后让每个身体点以相同的量向其前一个移动。这不起作用,我觉得我的算法本身有问题。我不熟悉这些中间随机游走,所以我大部分时间都是靠猜测。

this["moveCurve"] = function() {
    let newDir = this["oldDir"] + (random() - 1/2)*PI/6; 
    let velocity =  createVector(1,0); 
    velocity.setMag(5); 
    velocity.setHeading(newDir); 
    this["points"][3].add(velocity); 
    for (let i = 2; i >= 0; i--) { 
        this["points"][i].add(p5.Vector.sub(this["points"][i + 1],this["points"][i]).setMag(5)); 
    } 
    this["oldDir"] = newDir; 
}

如果您知道我可以做些什么来使这项工作正常进行,我很想听听您的建议。谢谢!

【问题讨论】:

标签: javascript simulation p5.js random-walk


【解决方案1】:

这看起来确实是一个算法问题/而不是你如何实现它的错误。

这是我解释为什么在这个算法中两点之间的差距必须减小的原因:

让我们只考虑一条两点蛇,在初始位置 Hi:(20, 0) 和 Ti:(0, 0) 处有两个点 Hi(头)和 Ti(尾)。所以,这里的标题是 0 弧度。

调用 moveCurve 时会发生什么?选择一个新的航向(让我们使用 PI/2,一个直角以便于想象)并使用 5 的固定速度我们计算 (20, 5) 的头部的新位置,我们称之为 Hf。 T 也移动,但它也以相同的 5 个单位速度向 Hf 移动,最终约为 (4.85, 1.21)。这两个最终位置之间的距离现在是 15.62657,小于初始距离。

为了形象化这一点,想想 Ti、Hi 和 Hf 之间形成的三角形。 Ti 和 Hi 构成了这个三角形的底。 Ti 将沿着斜边移动以到达 Tf,而 Hi 将沿着另一边移动。它们移动的方向形成一个小于 PI 弧度的角度,并且两个点都以相同的速度移动,因此直观地说,这些点必须越来越靠近。

那么如何解决呢?好吧,如果我们考虑我们的小蛇的运动,尾巴向一个不错的方向移动,但太远了。一种解决方案可能是缩放速度矢量,以保持点之间的固定距离,而不是使用固定速度。例如,在示例中不是沿着斜边从 Ti 向 Hf 步进 5 个单位,您可以沿着斜边从 Hf 向 Ti 步进 20 个单位。我不确定这对你的蛇有什么影响,只是一个想法!

继续滑行!

【讨论】:

  • 我想我明白了你的建议,但你的意思是 Hf 应该移动 20,而不是 Ti?
  • 我不小心在我认为你所指的句子中有一个流浪的 20。基本上,我建议 Tf 可以按如下方式计算:令 D = 一个从 Ti 指向 Hf 的单位向量。那么,Tf = Hf - D * 20
  • 我仍然不太确定这将如何帮助,在我的可视化中,这将使尾巴更快。无论如何,我还是根据 p5 文档上的示例找到了答案。
【解决方案2】:

幸运的是,p5 的文档本身已经为我提供了答案。通过修改 here 的代码以使用 p5 向量,我能够让它全部工作。

segLengths 属性是在制作对象时定义的,只取所有点之间的距离。

this["moveCurve"] = function() {
    let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
    let velocity = p5.Vector.fromAngle(newDir).setMag(5);
    this["points"][3].add(velocity);
    for (let i = 2; i >= 0; i--) {
      this["points"][i].set(p5.Vector.sub(this["points"][i+1], p5.Vector.fromAngle(p5.Vector.sub(this["points"][i+1],this["points"][i]).heading()).setMag(this["segLengths"][i])));
    }
    this["oldDir"] = newDir;
  }

我可能会花一点时间尝试清理一下代码,目前这对我的口味来说有点乱。但它有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多