弹丸运动-箭头


13

在2D游戏中,我只想绘制飞行中箭头的轨迹。使用下面的代码,轨迹(抛物线)看起来正确,但是角度(或旋转)或箭头不正确。

float g = -9.8f;
float x = (launchVelocity * time);
float y = (launchVelocity * time) + (0.5f * g * (float)Math.Pow(time, 2));
float angle = (float)Math.Tanh(y / x);

我想念什么?谢谢。


3
屏幕快照可能会有所帮助
doppelgreener 2011年

Answers:


10

Arctanh给您双曲线的切线!据我所知,你的抛物线不是双曲线。

但是我们有个好消息:找到抛物线的切线比较容易。等式是

x = s·t => t = x / s; y = s·t + g / 2·t²=> y = x + g / 2·x²/s²

你的在哪儿launchVelocity。现在,箭头的斜率是:

∂y/∂y= g /(2s²)·x + 1

Arctan如果愿意,您现在可以安全使用。

有关物理的一些其他信息:

您正在模拟的近似轨迹适用于箭头的质心。当您说“位置”(x,y)时,您是在说质心的位置。箭头的质心从中点稍微向前,如果要绘制箭头,则应将其考虑在内。

请记住,您没有考虑箭头的惯性动量(如果您发射巨型ball炮,则可能会发生很大变化),并且没有考虑箭头的流体动力学:弓箭飞行不会遵循抛物线运动!


谢谢Fxlll。知道从哪里可以获得适用于箭头物理的公式?
马丁

我认为您的意思是:![∂ y /∂ x = g /(2s²)· x + 1] [2],但是无论如何,我认为我在下面建议了一种更好的方法。一方面,您没有解释如何分离x和y分量,所以将其硬编码为任意45度角,launchVelocity并不是真正的launchVelocity,而是x和y中的分量
Dov

可以轻松计算出惯性矩。对于杆,这是两个,一个用于绕其质心旋转,另一个用于绕杆的轴旋转。叠加原理适用于惯性矩,因此箭头可以分为三部分:羽毛,身体和尖端。
FxIII 2011年

1
问题在于,唯一的动量是容易计算的,这是由于角度变化引起的。(您可以看到仅以一个常数项推导了两次抛物线)。另一个是由于后羽的旋转而引起的。在这里,羽毛阻力和摩擦都涉及到将动能转化为旋转运动,减慢了箭头速度,但增加了陀螺作用。这会影响轨迹并且很难建模
FxIII 2011年

无论如何,如果您可以将动量与设置了羽毛的速度相关联,则可以通过积分进行全部计算,但是我不确定您是否可以对运动方程采用封闭形式(即,您可以获得积分算法,但没有参数)方程)。
FxIII 2011年

4

您想要箭头在任何时间点的角度。您记得,为了计算角度,有一个切线。但是,这是您的思维开始出错的地方:

  1. 您想要的是delta y / delta x,因为斜率是变化率(在其他答案之一中提到)。请注意,x只是您随时处于的位置,而不是dx。

好的,所以如果您忽略空气摩擦,那么箭头的x速度就是一个常数。

首先,将速度分解为x和y分量。您可能以45度或60度的角度拍摄。因此,您需要launchVelocity和一个角度,它不是标量。

其次,将所有内容计算为两倍,而不是浮点数。您没有足够的数字技巧来知道舍入错误何时不会杀死您,因此请不要尝试。无论如何,这都不是节省时间的好方法。

第三,不要使用Math.pow,它很慢,而且不如乘以整数幂。另外,您可以使用霍纳表格节省大量时间(见下文)

final double DEG2RAD = Math.PI/180;
double ang = launchAngle * DEG2RAD;
double v0x = launchVelocity * cos(ang); // initial velocity in x
double v0y = launchVelocity * sin(ang); // initial velocity in y

double x = (v0x * time);
// double y = (v0y * time) + (0.5 * g * (float)Math.Pow(time, 2));
double y = (0.5 * g * time + v0y) * time

如果您渴望获得性能,甚至可以预先计算0.5 * g,但是上面的代码将带您完成90%的操作,而无需做任何太疯狂的事情。如果愿意的话,进行1000万次基准测试,虽然时间不是很长,但是从百分比的角度来看却相当大-Java中的库非常慢

因此,如果您想要箭头应该旋转的角度,那么您想要的就是

atan(dy/dx)

在这种情况下,这将起作用,因为dx是一个常数。但通常,dx可以为零,因此您通常要使用:

atan2(dy, dx)

这是专门为此工作设计的功能。

但是正如我说的那样,Java中的库函数非常慢,在这种情况下,还有一种更好的方法,而无需上面的@FxIII提及。

如果水平速度始终为v0x,垂直速度为:

double vy = v0y - 0.5 * g * time;

那么您的增量是:vx,vy

您不需要角度。如果要绘制箭头,请使用名义上类似的内容:

情节(x,y,x + vx,y + vy);

我不知道您要绘制什么内容,因此,如果确实需要旋转它的角度(例如使用JOGL),那么请确定使用该角度。

不要忘记您是否正在使用opengl将角度转回度,因为ATAN2返回弧度:

final double RAD2DEG = 180 / Math.PI;
double ang = Math.atan2(vy,vx); // don't forget, vy first!!!
double deg = ang * RAD2DEG;

2

Tanh()(双曲正切)将角度作为参数,但是您已将侧面的比例作为参数。

您真正想要的是使用双曲线反正切,该正切将边的比率作为参数,然后返回角度。(其名称可能是“ atanh”,“ atanh2”,“ arctanh”或其他类似名称;在不同的数学库之间似乎有很大差异)


不,您不想要任何夸张的东西
Dov

Gah,您绝对正确。我立即发现“基本三角函数的用法”错误,却错过了他所使用的功能对于其余方法完全不正确。
Trevor Powell

Tan()取一个角度。Atan采用三角形边比(正弦/余弦)。
3Dave 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.