我正在做一个小游戏,其中涉及到敌人AI的路径。我想使用三次Bezier曲线生成的路径,但需要一个公式,使敌人在任何曲线上以恒定的速度移动。我只知道在直线路径上不断移动,并生成bezier曲线,但我不知道如何让这两者很好地协同工作。
发布于 2015-07-12 06:56:02
这里的问题是,您选择了一条非线性曲线,您希望在该曲线上获得线速度。
有一些选项,例如将曲线近似为线性几何图形(如线段或圆弧),然后以线速度而不是实际曲线通过这些几何图形。使曲线变平以沿相对直行的方向行走:
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循环,并且不是对列表进行切片,而是检查列表上的特定间隔-两者都是更多的代码,但在谷歌和维基百科的帮助下相对容易实现。
https://stackoverflow.com/questions/31349035
复制相似问题