3

I have been making a mod for a game called Minecraft PE and I'm using it to learn. Before I show my code I want you to know that Y is the vertical axis and X and Z is horizontal. Here is some code I used:

Math.asin(Math.sin((fPosXBeforeMoved - sPosX) /
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + 
Math.pow(fPosZBeforeMoved - sPosZ, 2))));

I didn't use tan because sometimes it returns something like NaN at a certain angle. This code gives us the sine of the angle when I clearly used Math.asin. angle is a value between -1 and 1, and it works! I know it works, because when I go past the Z axis I was expecting and it did switch from negative to positive. However, I thought it's supposed to return radians? I read somewhere that the input is radians, but my input is not radians. I really want the answer to how my own code works and how I should have done it! I spent all day learning about trigonometry, but I'm really frustrated so now I ask the question from where I get all my answers from!

Can someone please explain how my own code works and how I should modify it to get the angle in radians? Is what I've done right? Am I actually giving it radians and just turned it into some sort of sine degrees type thing?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 2
    Welcome to StackOverflow! Very nice to see young enthusiasts getting involved in programming so early on :) That's all I really wanted to say other than hi. I am going to edit your post for formatting, and then I'll try and answer your question. Stay tuned! – rayryeng Aug 26 '14 at 02:18

1 Answers1

3

OK, let's give a quick refresher as to what sin and asin are. Take a look at this right-angle triangle in the diagram below:

Source: Wikipedia

By taking a look at point A of this right-angle triangle, we see that there is an angle formed between the line segment AC and AB. The relationship between this angle and sin is that sin is the ratio of the length of the opposite side over the hypotenuse. In other words:

sin A = opposite / hypotenuse = a / h

This means that if we took a / h, this is equal to the sin of the angle located at A. As such, to find the actual angle, we would need to apply the inverse sine operator on both sides of this equation. As such:

A = asin(a / h)

For example, if a = 1 and h = 2 in our triangle, the sine of the angle that this right triangle makes between AC and AB is:

sin A = 1 / 2

To find the actual angle that is here, we do:

A = asin(1 / 2)

Putting this in your calculator, we get 30 degrees. Radians are another way of representing angle, where the following relationship holds:

angle_in_radians = (angle_in_degrees) * (Math.PI / 180.0)

I'm actually a bit confused with your code, because you are doing asin and then sin after. A property between asin and sin is:

arcsin is the same as asin. The above equation states that as long as x >= -Math.PI / 2, x <= Math.PI / 2 or x >= -90, x <= 90 degrees, then this relationship holds. In your code, the argument inside the sin will definitely be between -1 to 1, and so this actually simplifies to:

(fPosXBeforeMoved - sPosX) / Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + 
Math.pow(fPosZBeforeMoved - sPosZ, 2));

If you want to find the angle between the points that are moved, then you're not using the right sides of the triangle. I'll cover this more later.


Alright, so how does this relate to your question? Take a look at the equation that you have in your code. We have four points we need to take a look at:

  • fPosXBeforeMoved - The X position of your point before we moved
  • sPosX - The X position of your point after we moved
  • fPosZBeforeMoved - The Z position of your point before we moved
  • sPosZ - The Z position of your point after we moved.

We can actually represent this in a right-angle triangle like so (excuse the bad diagram):

enter image description here

We can represent the point before you moved as (fPosXBeforeMoved,fPosZBeforeMoved) on the XZ plane, and the point (sPosX,sPosZ) is when you moved after. In this diagram X would be the horizontal component, while Z would be the vertical component. Imagine that you are holding a picture up in front of you. X would be the axis going from left to right, Z would be the axis going up and down and Y would be the axis coming out towards you and going inside the picture.

We can find the length of the adjacent (AC) segment by taking the difference between the X co-ordinates and the length of the opposite (AB) segment by taking the difference between the Z co-ordinates. All we need left is to find the length of the hypotenuse (h). If you recall from school, this is simply done by using the Pythagorean theorem:

h^2 = a^2 + b^2
h = sqrt(a^2 + b^2)

Therefore, if you refer to the diagram, our hypotenuse is thus (in JavaScript):

Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + Math.pow(fPosZBeforeMoved - sPosZ, 2));

You'll recognize this as part of your code. We covered sin, but let's take a look at cos. cos is the ratio of the length of the adjacent side over the hypotenuse. In other words:

cos A = adjacent / hypotenuse = b / h

This explains this part:

(sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2) + 
Math.pow(sPosZ - fPosZBeforeMoved, 2));

Take note that I swapped the subtraction of sPosX and fPosXBeforeMoved in comparison to what you had in your code from before. The reason why is because when you are examining the point before and the point after, the point after always comes first, then the point before comes second. In the bottom when you're calculating the hypotenuse, this doesn't matter because no matter which order the values are subtracted from, we take the square of the subtraction, so you will get the same number anyway regardless of the order. I decided to swap the orders here in the hypotenuse in order to be consistent. The order does matter at the top, as the value being positive or negative when you're subtracting will make a difference when you're finding the angle in the end.

Note that this division will always be between -1 to 1 so we can certainly use the inverse trigonometric functions here. Finally, if you want to find the angle, you would apply the inverse cosine. In other words:

Math.acos((sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2)
+ Math.pow(sPosZ - fPosZBeforeMoved, 2)));

This is what I believe you should be programming. Take note that this will return the angle in radians. If you'd like this in degrees, then use the equation that I showed you above, but re-arrange it so that you are solving for degrees instead of radians. As such:

angle_in_degrees = angle_in_radians * (180.0 / Math.PI)

As for what you have now, I suspect that you are simply measuring the ratio of the adjacent and the hypotenuse, which is totally fine if you want to detect where you are crossing over each axis. If you want to find the actual angle, I would use the above code instead.


Good luck and have fun!

Community
  • 1
  • 1
rayryeng
  • 102,964
  • 22
  • 184
  • 193
  • Thank you! I never knew I would get such a detailed answer so quickly, explaining all the wrong I have done! You are amazing! – Jaskaran Singh Aug 26 '14 at 15:34
  • Haha thanks :) Double check to see if my math is right. If it is, and you're happy, consider accepting my answer if it helped you. Click on the checkmark icon that's at the top of my post, to the left below the up and down voting arrows. – rayryeng Aug 26 '14 at 15:38
  • I don't know if this is the right place to write this, but since you know where I struggle: What is wrong with some other code I used? setVelZ(getPlayerEnt(), speed / Math.cos(getAngleMoving())); setVelX(getPlayerEnt(), speed / Math.sin(getAngleMoving())); – Jaskaran Singh Aug 27 '14 at 19:37
  • getanglemoving() just gets the angle using your solution to my problem only that I replaced the fbeforemoveds with fpos's . The fpos's are checked 10 times a second and the spos's are checked 10 times a second but not as the same time as the fpos's. So I have a angle that updates 10 times a second and is more accurate. I don't see nothing wrong. – Jaskaran Singh Aug 27 '14 at 19:46
  • also speed is blocks per 1/20 seconds. It's bassicly the hypotenuse, and I use the angle I'm going in to find x and z and add it or if its negative subtract from my current vel. – Jaskaran Singh Aug 27 '14 at 19:50
  • You're code doesn't work. If I do the fixed version of my code while imagining in my mind that from top down x is vertical and z is horizontal then find then set the velocity, I won't be teleported to the most furthest point available from my place which is where chunks don't exist and I fall out of the void, as I get NaN with your code. – Jaskaran Singh Aug 27 '14 at 21:51
  • @JaskaranSingh I have edited my code since we last spoke. I noticed a couple of mistakes. Did you check the latest edits? Don't use the stuff I had before. Had to swap operations for a bunch of things. I'll answer your questions later. I'm on the road – rayryeng Aug 27 '14 at 22:28
  • 1
    It's fine now, you helped understand what I needed to know. I thought that doing Math.Sin(o/h) would give me the sine of theta, but thanks to you I know that the sin of theta is o/h and the arcsine would give us the angle in whatever the language chooses to return. It's because I _think_ you got your x and z axis muddled up as in minecraft axes are jumbled around, so you where calculating the wrong angle. I now know the value of math and will probably be the only lesson I'll focus in. IT for now doesn't test me on my knowledge but RUBBISH software like windows movie maker and powerpoint. – Jaskaran Singh Aug 27 '14 at 22:44