在贝塞尔曲线上生成运动

时间:2015-07-10 19:43:06

标签: bezier

我正在制作一个涉及敌人AI路径的小游戏。我想使用使用Cubic Bezier曲线生成的路径,但需要一个公式,使得enemys以恒定速度在任何曲线上移动。我所知道的是直线路径上的不断运动,并产生贝塞尔曲线,但我不知道如何使两者协同工作。

1 个答案:

答案 0 :(得分:1)

这里的问题是你选择了非线性曲线,你想要线性速度

有一些选项,例如将曲线近似为线性几何(如线段或圆弧),然后以线性速度而不是实际曲线穿过它们。将曲线展平以相对直接行走:

lines = []
x=curve.getX(0), y=curve.getY(0), nx, ny
step=..., interval=1/step, t=step
while(t<=1) {
  nx = curve.getX(t)
  ny = curve.getY(t)
  lines.push( new line(x,y,nx,ny)
  x = nx
  y = ny
  t += interval
}

完成 - 我们现在有了曲线,表示为线性近似,我们可以开始沿着它移动。如果step足够小,则没有人会注意到。

或者,您可以构建一个查找表作为绘图程序的一部分,并记录该点处曲线的距离,这样您就可以通过二进制搜索其余部分以线性速度遍历曲线。你需要的“下一个地方”的曲线。比选项1更多的初始工作,但一旦开始移动肯定会更快。

function arcLength(t) {
  // true fact: computing the arc length of a bezier curve is not
  // a thing you want to end up implementing yourself. It's not hard,
  // but getting to a point where you undestand *why* it's not hard is
  // is certainly time consuming, and depending on how much your brain
  // is unwilling to just take maths at face value, definitely hard.
  // Use someone else's implementation, like this one:
  // https://github.com/Pomax/bezierjs/blob/gh-pages/lib/bezier.js#L87
}

Curve.draw = function() { 
  if (!this.curveLUT) {
    // form a LUT however you like. The following demonstration 
    // code uses something similar to the above flattening:
    for(i=0;i<LUT.length;i++) {
      t = i / (LUT.length-1)
      x = curve.getX(t)
      y = curve.getY(t)
      LUT.push({x:x, y:y, dist: arclength(t)})
    }    
  }
  this.curveLUT.foreach(point -> point.draw())
}

然后当我们需要以某种特定的速度走弯道时:

speed = ...
currentPos = SomeLUTindex
if (currentPos < LUT.length) {
  currentDist = LUT[currentPos].dist
  nextDist = currentDist + speed
  nextPos = binarySearch(LUT.slice(currentPos), "dist", nextDist)
}

使用:

binarySearch(List, property, target) {
  midIdx = (int) List.length/2
  mid = List[midIdx]
  curr = mid[property]
  if(curr === target) return midIdx
  if(curr > target) return binarySearch(List.slice(0,midIdx), property, target)
  if(curr < target) return midIdx + binarySearch(List.slice(midIdx), property, target)
}

这看起来可能很多,但二进制搜索会在ceil(log₂(n))中解决,最糟糕的情况是,所以即使在10000点的查找表上,这也会找到最多14个步骤的下一个点。对函数的优化也将它展开到一个直的for / while循环,而不是对列表进行切片但是检查它的特定间隔 - 两者都是更多的代码,但相对容易实现谷歌和维基百科的帮助很少。

相关问题