Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm making a version of SpaceInvaders and I would like my Shoots to have a diagonal movement. I tried to google it, but I can figure out how to do it.
I've got the class Entity:
public abstract class Entity extends Parent{
protected double x;
protected double y;
protected double dx;
protected double dy;
private Rectangle me = new Rectangle();
private Rectangle him = new Rectangle();
Image ref;
StackPane root;
ImageView content;
public Entity(Image ref,int x,int y, StackPane root) {
this.ref=ref;
this.root=root;
this.x = x;
this.y = y;
content = new ImageView();
content.setSmooth(true);
content.setImage(ref);
content.setScaleX(Game.scalar);
content.setScaleY(Game.scalar);
content.setTranslateX(this.x);
content.setTranslateY(this.y);
content.setRotate(0);
Game.root.getChildren().add(content);
}
public void move(long delta) {
this.x += (delta * this.dx) / 1000;
this.y += (delta * this.dy) / 1000;
content.setTranslateX(this.x);
content.setTranslateY(this.y);
}
Now, how could I set a diagonal movement? I printed the game with the Shoot Entity.
Thaks.
You should use trigonometry, in particular sin and cos. The standard java class Math has those methods.
For example, we could think that a bullet traveling from the bottom to the top is going at an angle of 90 degrees (0 is from left to right, 180 is from right to left and 270 is from top to bottom):
double angle = 90.0;
double angleInRadians = Math.toRadians(angle); // convert from degrees to radians
x += Math.cos(angleInRadians); // cos of 90 is 0, so no horizontal movement
y += Math.sin(angleInRadians); // sin of 90 is 1, full vertical movement
To go diagonal just use a different angle, for example with 60 degree the bullet will travel both horizontally and vertically:
double angle = 60.0;
double angleInRadians = Math.toRadians(angle); // convert from degrees to radians
x += Math.cos(angleInRadians); // cos of 60 is 0.58.., so a bit of horizontal movement
y += Math.sin(angleInRadians); // sin of 60 is 0.80.., a decent amount of vertical movement
Why sine and cosine? A visual representation.
The image below show what we want to achieve, basically find the delta x and delta y to add to our origin position in order to reach the destination position, which are not perpendicular to each other.
Now let's take a look at what sine and cosine represent:
(Source: Wikipedia.)
We can notice the similarities: the points O and P are respectively our origin and destination, while sin θ and cos θ corresponds to delta y and delta x.
Applying these concepts to our situation we end up with:
Sine and cosine require an angle, which will define the movement direction of our object.
They will return a value between -1 and 1, so we will need to multiply it with a coefficient if we want to change the object movement "speed".
Based on limited information you've provided, I'm assuming x and y are the coordinates of your spaceship, while dx and dy are coordinates of the projectile's target. You can use Math.atan2() to calculate rotation degree for a projectile image and supply it to content.setRotate() you have there.
// consider your spaceship an origin in coordinate system
double relativeX = this.dx - this.x;
double relativeY = this.y - this.dy;
double degree = Math.toDegrees(Math.atan2(relativeY, relativeX));
// rotate a projectile image counterclockwise from horizontal direction
content.setRotate(90 - degree);
Related
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've spent a pretty long time trying to figure out how to move a bullet based on an angle (In degrees)
I define radians as:
public static double toRadians(int angle) {
return (90.0 - angle) * (Math.PI / 180);
}
Here is the code where I actually move the bullet. xMov and yMov can be negative and are added onto the current position every tick.
I've never really worked with Radians, but found the above code to make 0 north, 90 east, etc, which is what I want. I just can't figure out why the bullet isn't going to correct direction. It appears that the X is correct but the Y isn't.
double x= Math.cos(Utilities.toRadians(mvmtAngle));
double y= Math.sin(Utilities.toRadians(mvmtAngle));
xMov += x* 4;
yMov += y* 4;
Thanks!
- tips
EDIT: The degree is being set fine (From the input)
EDIT 2:
Rendering code:
((Graphics2D)g).rotate(Utilities.toRadians(barrelAngle), xStart, yStart);
g.fillRect(xStart - 1, yStart, 2, BARREL_SIZE);
((Graphics2D)g).rotate(-(Utilities.toRadians(barrelAngle)), xStart, yStart);
The problem is probably that the +y direction on the screen is down, while I suspect that you want +y to be up. Your toRadians function converts 0 degrees to PI/2 radians, which on the screen is going down. Try using this conversion instead:
public static double toRadians(int angle) {
return (angle - 90.0) * (Math.PI / 180);
}
This just reverses the sign of the angle. Since Math.cos is an even function, it won't affect the computed x coordinate but will reverse the sense of the y coordinate.
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!
Let's say I have an (x,y) that is always the same for the start point of a line and an (x,y) that changes for the end point of that same line. The line is also always 40px long. At the start of the program the line originates in a vertical orientation (lets call it 0 degrees). Based on a user input I need the line to be redrawn a specific number of degrees from its origin by changing only the end (x,y).
SOME MORE FOOD FOR THOUGHT IF YOU NEED IT:
I'm in a rut trying to calculate this and make it work in Java. I can make the math work to calculate the point based on the arc length of a circle segment, but I don't know how to make Java do it.
I think it would work easier based off a triangle angles since I will always know the length of two sides of a triangle (one side formed by the 40px long line and the other side formed by the start point of that line and the border of the JPanel) and the angle those two lines form. Still, my brain is mush from trying to figure it out. Any help would be much appreciated.
UPDATE:
#casablanca got me on the right track. I brushed up on my trig functions and here is how I made it work.
First off, I didn't realize that 90 degrees was straight up, but once I did realize that I made my solution reflect that fact. I was drawing my line starting at the bottom center of the frame going out. Since the opposite side of the triangle is on the right side of the screen when the angle given by my user is less than 90 degrees and is on the left side of the screen when the angle given by my user is greater than 90 degrees I had to adjust the formula to account for that fact, thus I have four methods, one for the x coordinate on the left side of the screen (when the user given angle is greater than 90 degrees), one for the y coordinate on the left side of the screen (when the user given angle is greater than 90 degrees) and the same thing for the right side of the screen when the user given angle is less than 90 degrees. The int length in all methods is the length of the hypotenuse. Thanks again for your help #casablanca!
public double leftSideX(double angle, int length){
double x = frameWidth/2 - (length * Math.cos(Math.toRadians(90-(Math.toDegrees(angle)-90))));
return x;
}
public double leftSideY(double angle, int length){
double y = frameHeight - (length * Math.sin(Math.toRadians(90-(Math.toDegrees(angle)-90))));
return y;
}
public double rightSideX(double angle, int length){
double x = frameWidth/2 + (length * Math.cos(angle));
return x;
}
public double rightSideY(double angle, int length){
double y = frameHeight - (length * Math.sin(angle));
return y;
}
Is this what you're looking for?
startX = x;
startY = y;
endX = x + 40 * Math.sin(angle);
endY = y + 40 * Math.cos(angle);
And draw a line from (startX, startY) to (endX, endY) in whatever API you're using.
Also note that angle is in radians. If you had it in degrees, you need to convert it first:
angle = angle * Math.PI / 180;