What is the formula used to determining moving object's rotation angle from its velocity or vector direction of travel?
For example, if an airplane is moving toward position (x1,y1) = (200, 100) from position (x0, y0) = (0,0), which angle would the plane be facing?
By rotation angle you apparently mean azimuth. The function Math.atan2(dy, dx) is the right approach. In your example with p1 = (x1, y1) = (200,100) and p0 = (x0, y0) = (0,0), you'd want Math.atan2(y1 - y0, x1 - x0). This will return the angle in radians. To convert to degrees, multiply by 180 / Math.PI.
To get the angle between two points, you plug the points into this code:
var _radians:Number = Math.atan2(y2-y1, x2-x1);
"_radians" is the angle in radians.
To rotate a DisplayObject, you can use its rotation property, after converting the angle into degrees.
var _degrees:Number = _radians * ( 180 / Math.PI );
_displayObject.rotation = _degrees;
You may need to add a contant to the rotation to line up with your art.
Related
I create a 2d game similar to a classic diepio. I created a system for positioning the player's barrel in a specific direction. The updated angle is sent to the server. When the player clicks, the server creates a missile. This only works correctly when the barrel is attached to the center of the player's body. When I want to move the barrel away from the center of the body, there is a problem. I don't know how to update the server-side position where the projectile spawns.
In the image below, the barrel rotates around the center of the player's body. I marked the missile's flight path with the red line.
On this image, the barrels also have a rotation axis in the player's center, but have been shifted to the side. The green line marked the route the missile should take. Unfortunately, I don't know how to do it correctly.
How to update the projectile's spawn point by a given distance (e.g. 10) from the basic distance (if the barrel was not moved) based on the player's angle of rotation and his position?
Projectile spawn method:
float angle = (float) ((player.getRotation() + 90) * Math.PI / 180f);
float forceX = (float) Math.cos(angle);
float forceY = (float) Math.sin(angle);
spawnProjectile(player.getPosition().x + (forceX * 3f), player.getPosition().y + (forceY * 3f));
If I understood your question correctly, you want to find the two points marked in orange in the following image:
Since you know the direction in which the missiles should fly (the red line), the distance from the center position (e.g. 10) and you know that there is a 90° angle between the movement vector of the missile (red line) and the connection line between the two starting positions of the missiles (marked as black line in the image) you can calculate the resulting positions like this:
float angle = (float) ((player.getRotation() + 90) * Math.PI / 180f);
float forceX = (float) Math.cos(angle);
float forceY = (float) Math.sin(angle);
// the center point (start of the red line in the image)
float centerX = player.getPosition().x + (forceX * 3f);
float centerY = player.getPosition().y + (forceY * 3f);
float offsetFromCenterDistanceFactor = 1f; // increase this value to increase the distance between the center of the player and the starting position of the missile
// the vector towards one of the starting positions
float offsetX1 = forceY * offsetFromCenterDistanceFactor;
float offsetY1 = -forceX * offsetFromCenterDistanceFactor;
// the vector towards the other starting position
float offsetX2 = -offsetX1;
float offsetY2 = -offsetY1;
//spawn the upper missile
spawnProjectile(centerX + offsetX1, centerY + offsetY1);
//spawn the lower missile
spawnProjectile(centerX + offsetX2, centerY + offsetY2);
For more detail on the calculation of the orthogonal vectors see this answer.
I'm making a 2D topdown view shooter game with Java Swing. I want to calculate what angle the mouse pointer is compared to the center of the screen so some of my Sprites can look toward the pointer and so that I can create projectiles described by an angle and a speed. Additionally If the pointer is straight above the middle of the screen, I want my angle to be 0°, if straight to its right, 90°, if straight below 180°, and straight left 270°.
I have made a function to calculate this:
public static float calculateMouseToPlayerAngle(float x, float y){
float mouseX = (float) MouseInfo.getPointerInfo().getLocation().getX();
float mouseY = (float)MouseInfo.getPointerInfo().getLocation().getY();
float hypotenuse = (float) Point2D.distance(mouseX, mouseY, x, y);
return (float)(Math.acos(Math.abs(mouseY-y)/hypotenuse)*(180/Math.PI));
}
The idea behind it is that I calculate the length of the hypotenuse then the length of the side opposite of the angle in question. The fraction of the 2 should be a cos of my angle, so taking that result's arc cos then multiplying that by 180/Pi should give me the angle in degrees. This does work for above and to the right, but straight below returns 0 and straight left returns 90. That means that I currently have 2 problems where the domain of my output is only [0,90] instead of [0,360) and that it's mirrored through the y (height) axis. Where did I screw up?
You can do it like this.
For a window size of 500x500, top left being at point 0,0 and bottom right being at 500,500.
The tangent is the change in Y over the change in X of two points. Also known as the slope it is the ratio of the sin to cos of a specific angle. To find that angle, the arctan (Math.atan or Math.atan2) can be used. The second method takes two arguments and is used below.
BiFunction<Point2D, Point2D, Double> angle = (c,
m) -> (Math.toDegrees(Math.atan2(c.getY() - m.getY(),
c.getX() - m.getX())) + 270)%360;
BiFunction<Point2D, Point2D, Double> distance = (c,
m) -> Math.hypot(c.getY() - m.getY(),
c.getX() - m.getX());
int screenWidth = 500;
int screenHeight = 500;
int ctrY = screenHeight/2;
int ctrX = screenWidth/2;
Point2D center = new Point2D.Double(ctrX,ctrY );
Point2D mouse = new Point2D.Double(ctrX, ctrY-100);
double straightAbove = angle.apply(center, mouse);
System.out.println("StraightAbove: " + straightAbove);
mouse = new Point2D.Double(ctrX+100, ctrY);
double straightRight = angle.apply(center, mouse);
System.out.println("StraightRight: " + straightRight);
mouse = new Point2D.Double(ctrX, ctrY+100);
double straightBelow = angle.apply(center, mouse);
System.out.println("StraightBelow: " + straightBelow);
mouse = new Point2D.Double(ctrX-100, ctrY);
double straightLeft = angle.apply(center, mouse);
System.out.println("Straightleft: " + straightLeft);
prints
StraightAbove: 0.0
StraightRight: 90.0
StraightBelow: 180.0
Straightleft: 270.0
I converted the radian output from Math.atan2 to degrees. For your application it may be more convenient to leave them in radians.
Here is a similar Function to find the distance using Math.hypot
BiFunction<Point2D, Point2D, Double> distance = (c,m) ->
Math.hypot(c.getY() - m.getY(),
c.getX() - m.getX());
I need a way(in java) to calculate which direction my camera will move forward on the x and z axes based on the direction my camera is facing(yaw), and for y(the vertical axis), the pitch. I'm making my own game engine and my own camera.
With all values defaulting at zero, moving the camera correctly directs all movement along the positive z axis. However, when I pan the camera to the left or right(thereby changing the yaw), the camera still only moves along the z axis... So how do I calculate the change in direction to the x, y, and z axes?
The value range on the yaw is 0(south), 45(southwest), 90(west), 135(northwest), 180(north), 225(northeast), 270(east), 315(southeast), and back to 360(south, same as 0).
What I'm looking for with the compass directions(where a '+' or '-' indicates a change in value along that axis):
South = x, y, z+
SouthWest = x+, y, z+
West = x+, y, z
NorthWest = x+, y, z-
North = x, y, z-
NorthEast = x-, y, z-
East = x-, y, z
SouthEast = x-, y, z+
The value range on the pitch is 0.0(middle), 100.0(up all the way), and -100.0(down all the way).
If I need to post some code, I can, but it might get complicated. I hope I'm making some kind of sense so that someone can help me!
Suppose you want to move the camera in direction y with distance k.
For the sake of simplicity, i will convert your directions to angles, where 0.0 represents right, Pi/2 represents up, Pi represents left, 3*Pi/2 represents down and so.
EDIT: As you say y of camera will be affected only by the pitch. X and z, instead will be affected by both the yaw and the pitch.
You can calculate the new x, y and z by the following:
float y = // Yaw angle
float p = // Pitch angle
float k = // Move distance
float xzLength = cos(p) * k;
float dx = xzLength * cos(y);
float dz = xzLength * sin(y);
float dy = k * sin(p);
// Update your camera:
camera.x += dx;
camera.y += dy;
camera.z += dz;
Obviously, yaw and pitch do not change, so you don't need to update them.
I'm sorry if this question was asked before, I did search, and I did not find an answer.
My problem is, that I'd like to make movement on all 3 axes with the X and Y rotation of the camera being relevant.
This is what I did:
private static void fly(int addX, int addY){ //parameters are the direction change relative to the current rotation
float angleX = rotation.x + addX; //angle is basically the direction, into which we will be moving(when moving forward this is always the same as our actual rotation, therefore addX and addY would be 0, 0)
float angleY = rotation.y + addY;
float speed = (moveSpeed * 0.0002f) * delta;
float hypotenuse = speed; //the length that is SUPPOSED TO BE moved overall on all 3 axes
/* Y-Z side*/
//Hypotenuse, Adjacent and Opposite side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
//OppYZ is the opposite of this triangle, which is the ammount that should be moved on the Y axis.
//the Adjacent is not used, don't get confused by it. I just put it there, so it looks nicer.
float HypYZ = speed;
float AdjYZ = (float) (HypYZ * Math.cos(Math.toRadians(angleX))); //adjacent is on the Z axis
float OppYZ = (float) (HypYZ * Math.sin(Math.toRadians(angleX))); //opposite is on the Y axis
/* X-Z side*/
//Side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
float HypXZ = speed;
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); //on X
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); //on Z
position.x += AdjXZ;
position.y += OppYZ;
position.z += OppXZ;
}
I only implement this method when moving forwards(parameters: 0, 90) or backwards(params: 180, 270), since movement can't happen on the Y axis while going sideways, since you don't rotate on the Z axis. ( the method for going sideways(strafing) works just fine, so I won't add that.)
the problem is that when I look 90 degrees up or -90 down and then move forward I should be moving only on the Y axis(vertically) but for some reason I also move forwards(which means on the Z axis, as the X axis is the strafing).
I do realize that movement speed this way is not constant. If you have a solution for that, I'd gladly accept it as well.
I think your error lies in the fact that you don't fully project your distance (your quantity of movement hypothenuse) on your horizontal plane and vertical one.
In other words, whatever the chosen direction, what you are doing right now is moving your point of hypothenuse in the horizontal plane X-Z, even though you already move it of a portion of hypothenuse in the vertical direction Y.
What you probably want to do is moving your point of a hypothenuse quantity as a total.
So you have to evaluate how much of the movement takes place in the horizontal plane and how much in the vertical axis. Your direction gives you the answer.
Now, it is not clear to me right now what your 2 angles represent. I highly recommend you to use Tait–Bryan angles in this situation (using only yawn and pitch, since you don't seem to need the rolling - what you call the Z-rotation), to simplify the calculations.
In this configuration, the yawn angle would be apparently similar to your definition of your angleY, while the pitch angle would be the angle between the horizontal plane and your hypothenuse vector (and not the angle of the projection in the plane Y-Z).
A schema to clarify:
With :
s your quantity of movement from your initial position P_0 to P_1 (hypothenuse)
a_y the yawn angle and a_p the pitch one
D_x, D_y, D_z the displacements for each axis (to be added to position, ie AdjXZ, OppYZ and OppXZ)
So if you look at this representation, you can see that your triangle in X-Z doesn't have s as hypotenuse but its projection s_xz. The evaluation of this distance is quite straightforward: if you place yourself in the triangle P_0 P_1 P_1xz, you can see that s_xz = s * cos(a_p). Which gives you:
float HypXZ = speed * Math.cos(Math.toRadians(angleP))); // s_xz
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); // D_x
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); // D_z
As for D_y ie OppYZ, place yourself in the triangle P_0 P_1 P_1xz again, and you'll obtain:
float OppYZ = (float) (speed * Math.sin(Math.toRadians(angleP))); // D_y
Now, if by angleX you actually meant the angle of elevation as I suppose you did, then angleP = angleX and HypXZ = AdjYZ in your code.
With this correction, if angleX = 90 or angleX = -90, then
HypXZ = speed * cos(angleX) = speed * cos(90deg) = speed * 0;
... and thus AdjXZ = 0 and OppXZ = 0. No movement in the horizontal plane.
Note:
To check if your calculations are correct, you can verify if you actually move your point of the wanted quantity of movement (hypothenuse ie speed ie s). Using Pythagorean theorem:
s² = s_xz² + D_z² // Applied in the triangle P_0 P_1 P_1xz
= D_x² + D_y² + D_z² // Applied in the triangle P_0 P_1x P_1xz
With the definitions of the displacements given above:
D_x² + D_y² + D_z²
= (s * cos(a_p) * cos(a_y))² + (s * cos(a_p) * sin(a_y))² + (s * sin(a_p))²
= s² * (cos(a_p)² * cos(a_y)² + cos(a_p)² * sin(a_y)² + sin(a_p)²)
= s² * (cos(a_p)² * (cos(a_y)² + sin(a_y)²) + sin(a_p)²)
= s² * (cos(a_p)² * 1 + sin(a_p)²)
= s² * (cos(a_p)² + sin(a_p)²)
= s² * 1 // Correct
Hope it helped... Bye!
I am looking for an algorithm to draw regular polygon like triangle, quadrangle, pentagon, hexagon etc.
I guess it`s basically dealing with the fact that all polygon points are located on the line of the circle.
What`s the algorithm to calculate those N points for Polygon object?
After drawing a regular polygon I need to draw another regular polygon based on the first one but rotated by K degrees.
Use sin and cos:
double theta = 2 * Math.PI / sides;
for (int i = 0; i < sides; ++i) {
double x = Math.cos(theta * i);
double y = Math.sin(theta * i);
// etc...
}
To rotate just add a constant offset to the angle, i.e. theta * i + offset.
The vertices of an N-vertex polygon are located at the angles
(2*Math.PI*K)/N
where K goes from 0 to N-1, inclusive. The vertical coordinate can be calculated as a sine of the angle times the radius of the circumcircle; the horizontal coordinate is calculated the same way, except you need to multiply the radius by the cosine of the angle.
In order to turn your polygon by X degrees, convert X to radians, and add the result to the angle in the formula, like this:
(2*Math.PI*K)/N + Xrad
Finally, since the origin of the screen is in one of the corners, only a portion of your polygon is going to be visible. To avoid this, add an offset equal to the position of the circumcircle's center to each coordinate that you calculate.
sin, cos, radius, 2*PI / number of sides and a loop