Angle between 2 points related to a center point in libgdx - libgdx

I want to get the angle between point 1 and point 2 in relation to a center point. How do I do this using Vector2?
Vector2 center = new Vector2((float)Gdx.graphics.getWidth /2, (float)Gdx.graphics.getHeight /2);
Vector2 point1 = new Vector2(center.x, center.y + 200.0f);
Vector2 point2 = new Vector2(center.x + 200.0f, center.y);
It should be 90°, but how do I get that?

Vector2 center = new Vector2(500, 500);
Vector2 point1 = new Vector2(center.x, center.y + 200.0f);
Vector2 point2 = new Vector2(center.x + 200.0f, center.y);
point1.sub(center).nor();
point2.sub(center).nor();
float angle = (MathUtils.atan2(point1.y, point1.x) - MathUtils.atan2(point2.y, point2.x));
angle *= MathUtils.radiansToDegrees;
System.out.println(angle); // 90.0
The angle calculation can be looked up anywhere on the internet. For example here.
It works with one additional step that we perform before the calculation. We need to treat the center as the (0, 0) origin, by subtracting it from the points and normalize them afterwards.

Get the vector of both points and subtract there rotation/worldAngle. Something like this should do:
Vector2 v1 = point1.cpy().sub(origin);
Vector2 v2 = point2.cpy().sub(origin);
float angle1 = v1.angle();
float angle2 = v2.angle();
float angleBetween = Math.abs(angle1 - angle2));
//If the angle is more then 180 then comparing the other way around would be shorter.
if (angleBetween > 180)
angleBetween = 360 - angleBetween;

Related

How do I play an animation in a specific place controlled by actionscript?

I have this moving character and when I press a button I want it to shoot at a object pointed by the mouse. But the character is moving so I don't know how to make the animation in a specific place. I am using Flash, actionscript 2 or 3
There are many ways in which it can be done, but this one is known to be one of the simplest:
Given source point A and target point B:
Calculate distance between A and B
var distance:Number = computeDistance(A,B); //define your function where computeDistance returns the Pythagorean distance between A and B
Calculate x and y difference
var dx:Number = B.x - A.x;
var dy:Number = B.y - A.y;
// normalization. Think of this as a ratio of the legs relative to the hypotenuse
dx = dx / distance;
dy = dy / distance;`
Calcualate xSpeed and ySpeed by multiplying dx and dy with speedPerFrame (arbitrary)
var xSpeed:Number = dx*speedPerFrame;
var ySpeed:Number = dy*speedPerFrame;
Increment your object's x and y position using xSpeed and ySpeed in the main game loop (respectively). Make sure you add a check if the object has arrived at the destination point.

find angle and velocity for a parabola that meet specific range

i'm a little ashamed to ask this, but i have tried a lot of different things and can't make it work.
i have a game that shots a bullet, i have made the code that calculates the parabola trajectory given a an angle and a velocity, but i'm trying to make the calculus needed to get the angle and velocity needed to reach X point (the user enemy tank) and i'm unable to make it work as i need.
my current code is:
var startingPointX:Number = globalCoord.x;
var startingPointY:Number = globalCoord.y;
var targetX:Number = tankPlayer.x;
var targetY:Number = tankPlayer.y;
//distance between user and enemy tank
var distanceTarget = Math.sqrt(( startingPointX - targetX ) * ( startingPointX - targetX ) + ( startingPointY - targetY ) * ( startingPointY - targetY ));
var fixedVel = (distanceTarget/10)*2;
var fixedG = bullet.g;
// launch angle
var o:Number = -(Math.asin((0.5 * Math.atan(fixedG * distanceTarget / fixedVel * fixedVel))) * 180 / Math.PI);
bullet.init(startingPointX, startingPointY, o, fixedVel);
and the functions in the bullet object that actually position the bullet in the parabola trajectory is:
public function init(x, y:Number, rot:Number, speed:Number) {
// set the start position
var initialMove:Number = 35.0;
this.x = x + initialMove * Math.cos(2 * Math.PI * rot / 360);
this.y = y + initialMove * Math.sin(2 * Math.PI * rot / 360);
this.rotation = rot;
//get speed
dx = speed * Math.cos(2 * Math.PI * rot / 360);
dy = speed * Math.sin(2 * Math.PI * rot / 360);
//animation
lastTime = getTimer();
addEventListener(Event.ENTER_FRAME,moveBullet);
}
public function moveBullet(event:Event)
{
//get the time passed
var timePassed:int = getTimer() - lastTime;
lastTime += timePassed;
//move bullet
dy += g * timePassed / 1000;
this.x += dx * timePassed / 1000;
this.y += dy * timePassed / 1000;
//bullet past the top of the screen
if (this.y < 0)
{
deleteBullet();
}
}
any help would be really useful, thanks ! :D
Regards,
Shadow.
If this is a ballistics problem in the sense that you project a particle from point A with velocity v at an angle theta and you want it to hit a point T where the y coordinates of A and T match (ie they lie on a plane perpendicular to the vector of gravitational force vector) then you can calculate the required angle and velocity from this equation (See your wiki link where this is defined):
R = (v * v * sin(2 * theta))/g
Here R is the distance travelled in the x direction from your start point A . The problem you are facing is you are trying to interpolate a parabola through just 2 points. There are an infinite amount of parabolas that will interpolate 2 points while the parabola through 3 points is unique. Essentially there are an infinite amount of choices for velocity and angle such that you can hit your target.
You will either need to fix the angle, or the velocity of the bullet in order to use the above equation to find the value you require. If not, you have an infinite number of parabolas that can hit your target.
The above assumes that air resistance is ignored.
EDIT : Thus if you know velocity v already you can get theta from simple rearrangement of the above :
( asin(g * R / (v * v)) ) / 2 = theta
Based on the suggestion from #mathematician1975 i resolved the code to this and works perfectly :D
var distanceTarget = startingPointX - targetX ;
var fixedVel = 100;
var fixedG = tmpB.g;
var o:Number = (0.5 * Math.atan((fixedG * distanceTarget / (fixedVel * fixedVel)))) * 180 / Math.PI;
//this is only necessary why the enemy tank is facing left
o -= 180;
what i made is:
set a fixed velocity as #mathematician1975 said, a lot bigger than before
the distance between starting and ending point is lineal and not using Pythagoras.
the -180 is just why the enemy tanks is facing left.
i hope someone would find it useful in the future :D
Regards,
Shadow.

Strafe Around a Point

This seems like a simple trig question, but for whatever reason, things aren't working out.
I'm trying to simply have an object rotate around a given point when the user presses the A/D keys (strafing around the mouse in a circular motion, while still facing the mouse).
Here's the code I've tried so far (all Math functions take and return radians):
if (_inputRef.isKeyDown(GameData.KEY_LEFT))
{
x += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x) - Math.PI * 0.5);
y += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x) - Math.PI * 0.5);
}
else if (_inputRef.isKeyDown(GameData.KEY_RIGHT))
{
x += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x) + Math.PI * 0.5);
y += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x) + Math.PI * 0.5);
}
And a more elegant method which accomplishes the same thing:
if (_inputRef.isKeyDown(GameData.KEY_LEFT))
{
x += 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x));
y -= 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x));
}
else if (_inputRef.isKeyDown(GameData.KEY_RIGHT))
{
x -= 2 * Math.sin(Math.atan2(mouseY - y, mouseX - x));
y += 2 * Math.cos(Math.atan2(mouseY - y, mouseX - x));
}
Now, they both kind of work, the object rotates around the mouse while always facing the mouse, but given enough time of holding down the strafe button, it becomes increasingly apparent that the object is also rotating AWAY from the mouse, as if its being pushed away.
I have no idea why this is and how to fix it.
Any insight is appreciated!
I think your current approach would only work if you take 'infinitely small' steps. As it is now, each movement is perpendicular to the "to-mouse vector" and thus increases the distance between mouse and object.
A solution would be to calculate the new position while keeping the distance to the mouse unchanged, by rotating the position around the mouse:
// position relative to mouse
var position:Point = new Point(
x - mouseX,
y - mouseY);
var r:Number = position.length; // distance to mouse
// get rotation angle around mouse that moves
// us "SPEED" unit in world space
var a:Number = 0;
if (/* LEFT PRESSED */) a = getRotationAngle( SPEED, r);
if (/* RIGHT PRESSED */) a = getRotationAngle(-SPEED, r);
if (a > 0) {
// rotate position around mouse
var rotation:Matrix = new Matrix();
rotation.rotate(a);
position = rotation.transformPoint(position);
position.offset(mouseX, mouseY);
x = position.x;
y = position.y;
}
// elsewhere...
// speed is the distance to cover in world space, in a straight line.
// radius is the distance from the unit to the mouse, when rotating.
private static function getRotationAngle(speed:Number, radius:Number):Number {
return 2 * Math.asin(speed / (2 * radius));
}
The above uses a Matrix to rotate the (x, y) position around the mouse position. Ofcourse you can apply the same principle without using Matrix if so desired.
I had to do some trig to come up with the right equation for getting the correct angle. The angle depends on the radius of the movement arc, since a larger radius but constant angle would increase the movement distance (undesired behavior). My earlier solution (before edits) was to scale the angle by the radius, but that would still result in slightly more movement with larger radii.
The current approach ensures that radius and speed remain constant in all cases.

Incrementing points along a line

I'm calculating increments from point A (top right) to point B (bottom left) with the following code. But as we get closer to point B, my increments get further and further off the expected path. The green line in the picture is the expected path of the white dot.
public function get target():Point { return _target; }
public function set target(p:Point):void
{
_target = p;
var dist:Number = distanceTwoPoints(x, _target.x, y, _target.y); //find the linear distance
//double the steps to get more accurate calculations. 2 steps are calculated each frame
var _stepT:Number = 2 * (dist * _speed); //_speed is in frames/pixel (something like 0.2)
if (_stepT < 1) //Make sure there's at least 1 step
_stepT = 1;
_stepTotal = int(_stepT); //ultimately, we cannot have half a step
xInc = (_target.x - x) / _stepT; //calculate the xIncrement based on the number of steps (distance / time)
yInc = (_target.y - y) / _stepT;
}
private function distanceTwoPoints(x1:Number, x2:Number, y1:Number, y2:Number):Number
{
var dx:Number = x1-x2;
var dy:Number = y1-y2;
return Math.sqrt(dx * dx + dy * dy);
}
Basically, I'm out of ideas. The only thing that seems to get the white dot to follow the green line exactly is to adjust the target's position like so:
distanceTwoPoints(x, _target.x + 2, y, _target.y + 1);
//...
xInc = (_target.x + 2 - x) / _stepT;
yInc = (_target.y + 1 - y) / _stepT;
However, this throws off other parts of the simulation where there is no angle between points, like coming into point A (top right). This makes me think the distance between the two points needs to be calculated as shorter than it actually is. Any ideas?
Flash has a great function that is really handy for this. Point.interpolate(pointA, pointB, number) It returns a point between points A and B. The third input (Number) is how close to pointA or pointB the resulting point should be, from 0 to 1. You'll have to calculate its value.
What interpolate does is basically a weighted average of the two input points, the number being the weight towards one point. If the number is 0.5, you'll get a point halfway between the two input points. 1 returns PointA, 0 returns PointB.
flash.geom.Point.interpolate() for details.
For other languages, or math in general, you can do it this way, no Trig required: point1, the origin, and point2 the end point. point3 is a point between point1 and point2. loc is a ratio from point1 to point2, how far down the line to go. loc = .25 would be a quarter of the way from point1 towards point2. point3.x = point1.x * (1 - loc) + point2.x * loc and point3.y = point1.y * (1 - loc) + point2.y * loc. This will even work for values outside of 0-1, such as a point on the line connecting point1 and point2 but not between them.

How to calculate third point on line using atan2?

I'm trying to animate some bitmaps out in relation to a center point. They don't all start at that center point, but I want them to fly out as though a force from that center point slammed into them and pushed them outwards radially, such that they fly completely off the stage.
So: I know the center point, and the x and y position of each bitmap arranged around it. For each one I can draw a line from the center to that x,y point. I should then be able to get the angle formed by that line to the horizontal, and then set a destination point farther out on that line. The bitmap will be tweened out to that point. I believe that that is what Math.atan2 is for.
Here's what I've got as I iterate through the array of bitmaps (i is an object):
var angle:Number = Math.atan2(i.bitmap.y - centerY, i.bitmap.x - centerX) * 180 / Math.PI;
var dist:Number = 200; //arbitrary number, just to test
destX = centerX + dist * Math.cos(angle); //destination x
destY = centerY + dist * Math.sin(angle); //destination y
Instead of these things gliding out radially, they're jumping around.
I'm having trouble understanding atan2 and exactly what I'm doing wrong.
Thanks,
David
You can achieve the same effect without trigonometric functions using just vector operations:
var dist:Number = 200; //arbitrary number, just to test
var dx:Number = i.bitmap.x - centerX;
var dy:Number = i.bitmap.y - centerY;
var length:Number = Math.sqrt( dx*dx + dy*dy );
var normalizeddx:Number = dx / length;
var normalizeddy:Number = dy / length;
destX = centerX + dist * normalizeddx; //destination x
destY = centerY + dist * normalizeddy; //destination y
This should be much faster, than using trigonometric functions. I don't know the language specifics of actionscript, so probably this can be optimized more.
Try removing the *180/PI to keep the angle in radians.
var angle:Number = Math.atan2(i.bitmap.y-centerY, i.bitmap.x - centerX);
Then change destX and destY to
destX = i.bitmap.x + dist * Math.cos(angle);
destY = i.bitmap.y + dist * Math.sin(angle);
atan2 could work in this situation I suppose but I would just use atan:
var angle:Number = Math.atan((i.bitmap.y - centerY) / (i.bitmap.x - centerX));
ADDITION:
Code I just saw on another forum that appears to do what you want (there's only a slight difference from what you wrote in the first place)
var angle:Number = Math.atan2(mouseX,mouseY-180)-Math.PI/2;
var xNew:Number = 20*Math.cos(angle);
var yNew:Number = -20*Math.sin(angle);
You have to get rid of the *180/Math.PI part. The angle has to be in radians. So the first line would look like
var angle:Number = Math.atan2(i.bitmap.y - centerY, i.bitmap.x - centerX);
The rest should be fine.