我正在写一个2D游戏,我在相机空间里有鸟.我想让它们飞起来.所以,我生成3~随机点.第一个是左上侧,第二个是中底,第三个是右上.
结果我有180度旋转三角形.
为了使一只鸟在曲线的路径上移动,我有一个t参数,它在每个帧(渲染循环)中增加一些增量.
问题是在不同的曲线中,鸟类的速度不同.如果三角形是"宽"(1)它们更慢,如果它被Y坐标(2)拉伸,速度非常快.

但我想在不同的曲线上使速度相等.从逻辑上讲,我必须改变delta每条曲线附加的每一帧.
我试图像这样解决它:
通过求和2个向量的长度来找到曲线的长度:P1P2和P2P3.
比我已经定义了每帧1个虚拟仪表的速度.一个小伪代码:
float pixelsInMeter = 92.f; // One virtual meter equals to this number of pixels
float length = len(P1P2) + len(P2P3)
float speed = 0.0003f; // m/frame
// (length * speed) / etalon_length
float speedForTheCurve = toPixels( (toMeters(length) * speed) / 1.f);
// ...
// Each frame code:
t += speedForTheCurve;
Vector2 newPos = BezierQuadratic(t, P1, P2, P3);
Run Code Online (Sandbox Code Playgroud)
但是鸟无论如何都有不同的速度.怎么了?或者也许有更好的方法.
您使用的贝塞尔函数是一个边界为 [0...1] 的参数化函数。你搞乱了步长,这就是你获得疯狂速度的原因。一般来说,距离d是方程中的因变量,这对我来说,它们的速度会根据曲线的长度而不同。
由于速度是因变量,我们将通过计算步长来向量化您的函数。
查看这个伪代码:
P1 = (x1, y1)
P2 = (x2, y2)
P3 = (x3, y3)
int vec[100][2]
int getPoint(int p1, int p2, float stepSize) {
return p1 + (p2 - p1)*stepSize;
}
for (float i = 0.0; i < 1.0; i += 0.01 ) {
int newX = getPoint(getPoint(x1, x2, i), getPoint(x2, x3, i), i);
int newY = getPoint(getPoint(y1, y2, i), getPoint(y2, y3, i), i);
vec[iter++][0] = newX;
vec[iter][1] = newY;
}
Run Code Online (Sandbox Code Playgroud)
您可以通过执行一阶差分来获取增量值,但我认为这是没有必要的。只要您根据步骤迭代将所有小鸟移动适当的距离,它们都会移动不同的距离,但它们的轨迹将相同地开始和结束。
根据您的方程,我们可以计算像素增量步长:
int pixelsToMove = toMeter(sqrt((x2 - x1)^2 + (y2 - y1)^2))/pixelsInMeter;
Run Code Online (Sandbox Code Playgroud)
这将为您提供适当数量的像素来移动小鸟。这样他们都会移动不同的步长,但速度会不同。那有意义吗?
或者,尝试这样的事情(更难):
xy对两个直角坐标之间的二次积分让我们从二次的东西开始:
y = Ax^2 + Bx + C其中A != 0,因此由于您有三个点,因此您将需要三个方程。使用代数,您可以求解以下常数:
A = (y3 - y2)/((x3 - x2)(x3 - x1)) - (y1 - y2)/((x1 - x2)(x3 - x1))
B = (y1 - y2 + A(x2^2 - x1^2))/(x1 - x2)
C = y1 - Ax1^2 - Bx1
然后您可以使用上面的公式来获得闭合形式的弧长。查看这个网站,wolfram 将为您集成它,您只需输入:
现在您已经计算了弧长,请转换actualArcLength为速度或您使用的任何单位:
float speedForTheCurve = toPixels( (toMeters(actualArcLength) * speed) / 1.f);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
588 次 |
| 最近记录: |