我一直在制作一款名为Minecraft PE的游戏,我正在用它来学习。在我展示代码之前,我想让您知道Y
是纵轴,X
和Z
是水平的。这是我使用的一些代码:
Math.asin(Math.sin((fPosXBeforeMoved - sPosX) /
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) +
Math.pow(fPosZBeforeMoved - sPosZ, 2))));
我没有使用tan
,因为有时会以某个角度返回NaN
之类的内容。当我清楚地使用Math.asin
时,这段代码给了我们角度的正弦。 angle
是介于-1和1之间的值,它可以正常工作!我知道它有效,因为当我经过Z轴时,我期待并且它确实从负变为正。但是,我认为它应该返回弧度?我读到某处输入是弧度,但我的输入不是弧度。我真的想要回答我自己的代码如何工作以及我应该如何做到这一点!我花了一整天学习三角学,但我真的很沮丧,所以现在我问问我从哪里得到我的答案!
有人可以解释我自己的代码是如何工作的,以及我应该如何修改它以获得弧度的角度?我做得对吗?我实际上给它弧度,然后把它变成某种正弦度类型的东西吗?
答案 0 :(得分:3)
好的,让我们快速回顾sin
和asin
是什么。看看下图中的这个直角三角形:
来源:Wikipedia
通过查看此直角三角形的点A
,我们可以看到线段AC
和AB
之间形成了一个角度。该角度与sin
之间的关系是sin
是相对边长度与斜边的长度之比。换句话说:
sin A = opposite / hypotenuse = a / h
这意味着,如果我们选择a / h
,则等于位于sin
的角度的A
。因此,要找到实际角度,我们需要在此等式的两边应用逆正弦算子。就这样:
A = asin(a / h)
例如,如果我们的三角形中有a = 1
和h = 2
,则此右三角形在AC
和AB
之间的角度正弦为:
sin A = 1 / 2
要找到此处的实际角度,我们会这样做:
A = asin(1 / 2)
把它放在你的计算器中,我们得到30度。弧度是表示角度的另一种方式,其中包含以下关系:
angle_in_radians = (angle_in_degrees) * (Math.PI / 180.0)
我实际上对您的代码感到困惑,因为您之后正在asin
然后sin
。 asin
和sin
之间的属性为:
arcsin
与asin
相同。上面的等式表明只要x >= -Math.PI / 2, x <= Math.PI / 2
或x >= -90, x <= 90
度,那么这种关系就成立了。在您的代码中,sin
内的参数肯定介于-1到1之间,因此实际上简化为:
(fPosXBeforeMoved - sPosX) / Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) +
Math.pow(fPosZBeforeMoved - sPosZ, 2));
如果要查找移动点之间的角度,则不要使用三角形的右侧。我稍后会详细介绍。
好的,那么这与你的问题有何关系?看一下代码中的等式。我们有四点需要看一下:
fPosXBeforeMoved
- 我们移动之前您的观点的X
位置sPosX
- 我们移动后您的观点的X
位置fPosZBeforeMoved
- 我们移动之前您的观点的Z
位置sPosZ
- 我们移动后你的观点的Z
位置。 我们实际上可以在这样的直角三角形中表示这一点(原谅不好的图表):
我们可以代表您在(fPosXBeforeMoved,fPosZBeforeMoved)
平面上移动XZ
之前的点,而(sPosX,sPosZ)
就是您移动之后的点。在此图中,X
将是水平组件,而Z
将是垂直组件。想象一下,你正在你面前拍照。 X
将是从左到右的轴,Z
将是向上和向下的轴,Y
将是朝向您的轴并进入图片内部。
我们可以通过取AC
坐标和相对(X
)段的长度之间的差异来找到相邻(AB
)段的长度Z
坐标之间的差异。我们剩下的就是找到斜边的长度(h
)。如果你从学校回忆起来,这只是通过使用毕达哥拉斯定理来完成的:
h^2 = a^2 + b^2
h = sqrt(a^2 + b^2)
因此,如果您参考图表,我们的斜边因此(在JavaScript中):
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + Math.pow(fPosZBeforeMoved - sPosZ, 2));
您会将此识别为代码的一部分。我们介绍了sin
,但让我们来看看cos
。 cos
是相邻边长于斜边的长度比。换句话说:
cos A = adjacent / hypotenuse = b / h
这解释了这一部分:
(sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2) +
Math.pow(sPosZ - fPosZBeforeMoved, 2));
请注意,我交换减去sPosX
和fPosXBeforeMoved
与您之前的代码相比。原因是因为当您检查之前和之后的点,总是先到之后的点,那么之前的点是第二个。在你计算斜边的底部,这并不重要,因为无论从哪个顺序减去数值,我们都取减法的平方,所以无论如何你都会得到相同的数字。订购。我决定在斜边交换订单,以保持一致。订单确实在顶部很重要,因为当您进行减法时,正值或负数值会在您最终找到角度时产生影响。
请注意,此除法始终介于-1到1之间,因此我们当然可以使用反三角函数。最后,如果要查找角度,则应用反余弦。换句话说:
Math.acos((sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2)
+ Math.pow(sPosZ - fPosZBeforeMoved, 2)));
这就是我认为你应该编程的东西。请注意,这将返回角度以弧度。如果您在度数中喜欢这个,那么请使用我在上面显示的等式,但重新排列它以便您解决度数而不是弧度。就这样:
angle_in_degrees = angle_in_radians * (180.0 / Math.PI)
至于你现在拥有的东西,我怀疑你只是测量相邻和斜边的比例,如果你想检测你在每个轴上的交叉点,那就完全没问题了。如果你想找到实际的角度,我会改用上面的代码。
祝你好运,玩得开心!