I had written before about implementing a map in my libgdx project.
I did that using a snapshot of said google map, importing the GPS bounds of the snapshot, the route-latlong values, a locationservice (via interface) and the snapshot as Gdx.files.local string.
Hopefully, the last issue I have right now is that the route is rotated about 45 degrees clockwise. Otherwise my 'enemies' walk a perfect path. I already figured out that I had to 'flip' my y-axis; before that it was rotated AND flipped upside down.
I was hoping someone here with more experience might have dealt with something similar before and has some advice :)
This is basically the code that creates a Waypoint array, after converting the GPS coordinates to pixel-coordinates that correspond to the gps-bounds of the map-snapshot (bottom-left-corner and upper-right-corner see here, as well as the width and height of the map-texture.
private void convertPathToScreen(double[] gpsRoute){
for(int i = 0; i<gpsRoute.length; i++){
if(i % 2 != 0) {
screenRouteCoordinates[i] =
x_GpsToScreenConversion(gpsRouteCoordinates[i]);
}
else{
screenRouteCoordinates[i] =
y_GpsToScreenConversion(gpsRouteCoordinates[i]);
}
}
}
public int x_GpsToScreenConversion(double x_pointInGpsCoords){
double percentage = 1 - Math.abs((x_pointInGpsCoords - x_GpsMin) /
(x_GpsMax - x_GpsMin));
return (int)((percentage* Math.abs(mapWidth - mapOrigin)) + mapOrigin);
}
public int y_GpsToScreenConversion(double y_pointInGpsCoords){
double percentage = (y_pointInGpsCoords - y_GpsMin) / (y_GpsMax - y_GpsMin);
return (int)((percentage* Math.abs(mapHeight - mapOrigin)) + mapOrigin);
}
Edit: Now that I think of it, the error might be in my pathfinding code, although I tested it before moving my project forward and it worked solidly for all values I put in. Anyway, for completness...es sake
private void calculatePathing(){
angle = (float) (Math.atan2(waypointsToGoal[waypoint].y - getY(), waypointsToGoal[waypoint].x - getX()));
velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);
}
So the question is basically: How do I fix the 90° clockwise rotation that buggers up my game? Can I rotate the coordinates of the array around the center of the map (where all enemies walk to) or is there a mistake in the conversion-code here?
Solution: (Patchwork, but it gets the job done!)
I simply rotated my waypoints by the degree I needed around the destination-point. It doesn't solve the underlying issue, but it solves the symptom.
private void createWaypointArray(){
//formula requires radians
double angle = Math.toRadians(90);
double current_x;
double current_y;
// waypointCache.size()-1 gets me the last waypoint, the destination around which I rotate
double center_x = waypointCache.get(waypointCache.size()-1).x;
double center_y= waypointCache.get(waypointCache.size()-1).y;
// Loop through Vector2 Array, rotate the points around destination and save them
for(int i = 0; i < waypointCache.size()-1; i++){
current_x = waypointCache.get(i).x;
current_y = waypointCache.get(i).y;
waypointCache.get(i).x = (float)((current_x-center_x) * Math.cos(angle) - (current_y-center_y) * Math.sin(angle) + center_x);
waypointCache.get(i).y = (float)((current_x-center_x) * Math.sin(angle) + (current_y-center_y) * Math.cos(angle) + center_y);
// this does work, but also translates the points because it rotates around the
// worldaxis, usable when points lie on normal kartesian axis I guess
// waypointCache.get(i).rotate(90);
}
this.wayPointArray = waypointCache.toArray(new Vector2[waypointCache.size()]);
}
Related
I'm trying to do some basic trigonometry with Java and LibGDX on android.
I've spent a long time googling "How to find an angle in right triangles".
I still don't really understand :(
I want to give an Actor subclass a random direction to follow. So what is the angle - and what should I set xSpeed and ySpeed to, in order to move at the correct angle.
I started writing an app to help me see how it works.
There are two objects - An origin point and a touch point. User presses screen, touchPoint moves to where user touched. Methods fire to figure out the appropriate values. I know the XDistance and YDistance between the two points. That means I know the Opposite length and the Adjacent length. So all I need to do is tan-1 of (opposite / adjacent), am I right?
I just don't understand what to do with the numbers my program spits out.
Some code:
In create event of main class:
stage.addListener(new ClickListener() {
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
touchPoint.setX(x);
touchPoint.setY(y);
touchPoint.checkDistance(); // saves x and y distances from origin in private fields
atan2D = getAtan2(touchPoint.getYDistance(), touchPoint.getXDistance());
tanhD = getTanh(touchPoint.getYDistance(), touchPoint.getXDistance());
xDistanceLbl.setText("X Distance: " + touchPoint.getXDistance());
yDistanceLbl.setText("Y Distance: " + touchPoint.getYDistance());
atan2Lbl.setText("Atan2: " + atan2D);
tanhLbl.setText("Tanh: " + tanhD);
angleLbl.setText("Angle: No idea");
}
})
...
private double getAtan2(float adjacent, float opposite) {
return Math.atan2(adjacent, opposite);
}
private double getTanh(float adjacent, float opposite) {
return Math.tanh((adjacent / opposite));
}
These two functions give me numbers between (atan2: -pi to pi) and (tanh: -1.0 to 1.0)
How do I turn these values into angles from which I can then work backwards and get the opposite and adjacent again?
Doing this should allow me to create and object with a random direction, which I can use in 2D games.
atan2 gives you direction in radians. Direction from origin (0,0) to touchPoint. If you need direction from some object to touchPoint, then subtract object coordinates. Perhaps you also want to see direction in degrees (this is only for human eyes)
dx = x - o.x
dy = y - o.y
dir = atan2(dy, dx)
dir_in_degrees = 180 * dir / Pi
I you have direction and want to retrieve coordinate differences, you need to store distance
distance = sqrt(dx*dx + dy*dy)
later
dx = distance * cos(dir)
dy = distance * sin(dir)
But note that often storing dx and dy is better, because some calculations might be performed without trigonometric functions
Just noticed - using tanh is completely wrong, this is hyperbolic tangent function, it has no relation to geometry.
You can use arctan, but it gives angle in half-range only (compared with atan2)
I'm meant to draw a pentagon with lines going from the vertices to the centre. These 'arms' are being drawn correctly but when I try to connect the vertices it is being drawn incorrectly. To connect the lines I placed another draw function in the loop as below, which should take the end point coordinates of the first line drawn as the starting point, and the end point coordinates of the next 'arm' that is drawn in the iteration, as its end point. Am I missing something here? Am I wrong the use 'i+angle' in the second draw?
for (int i = 0; i < arms; i += angle) {
double endPointX = armLength * Math.cos(i*angle-Math.PI/2);
double endPointY = armLength * Math.sin(i*angle-Math.PI/2);
double endPointX2 = armLength * Math.cos((i+angle)*angle-Math.PI/2);
double endPointY2 = armLength * Math.sin((i+angle)*angle-Math.PI/2);
g2d.drawLine(centreX, centreY,centreX+ (int) endPointX,centreY+ (int) endPointY);
g2d.drawLine(centreX+ (int) endPointX,centreY+ (int) endPointY, (int) endPointX2,(int) endPointY2);
}
I have a solution for this here in PolygonFactory
Abstractly, the way to generate a regular polygon with n points is to put these points on the unit circle. So:
Calculate your angle step, which is 2 * pi / #vertices
Calculate your radius
Starting at angle 0 (or an offset if you want) use Math.sin(angle) and Math.cos(angle) to calculate the x and y coordinates of your vertices
Store the vertex points somewhere / somehow. If you look at the Polygon class or the class I wrote, you can get some ideas on how to do this in a way that is friendly to converting to a java.awt.Polygon.
I have a float[] newCoords variable that has a size of 9. The first 3 entries represent one vertex, the next 3 represent the second vertex and the last 3 represent the last vertex.
I have some code that is supposed to rotate a triangle anywhere in space when I feed it the coordinates. It looks like this:
float s = (float) Math.sin(0.5);
float c = (float) Math.cos(0.5);
float[] centroid = getCentroid(newCoords);
newCoords[0] -= centroid[0];
newCoords[1] -= centroid[1];
newCoords[3] -= centroid[0];
newCoords[4] -= centroid[1];
newCoords[6] -= centroid[0];
newCoords[7] -= centroid[1];
newCoords[0] = (newCoords[0] * c) - (newCoords[1] * s);
newCoords[1] = (newCoords[0] * s) + (newCoords[1] * c);
newCoords[3] = (newCoords[3] * c) - (newCoords[4] * s);
newCoords[4] = (newCoords[3] * s) + (newCoords[4] * c);
newCoords[6] = (newCoords[6] * c) - (newCoords[7] * s);
newCoords[7] = (newCoords[6] * s) + (newCoords[7] * c);
newCoords[0] += centroid[0];
newCoords[1] += centroid[1];
newCoords[3] += centroid[0];
newCoords[4] += centroid[1];
newCoords[6] += centroid[0];
newCoords[7] += centroid[1];
The problem is, its not rotating it properly, the triangles are spinning and getting smaller and smaller until they disappear for some reason, can anyone see why this is happening?
EDIT: whoops, almost forgot, here is my getCentroid() method.
private float[] getCentroid(float[] p1) {
float[] newCoords = new float[] {(p1[0] + p1[3] + p1[6]) / 3.0f,
(p1[1] + p1[4] + p1[7]) / 3.0f, 0};
return newCoords;
}
I see two problems with your code. Both are fixed with a little change.
You try to apply a rotation operation, taking X and Y coordinates as input and having the new X and Y as output. For every vertex you rotate, you have two lines of code: the first computes the X, the second the Y coordinate. But when computing the Y coordinate, you use the already rotated X coordinate! That's wrong.
There is also a numerical problem. You reuse the old values again and again, resulting in a chain of rotation computations a value makes though, so the numerical errors sum up. Never rely on such computations to work as expected. Instead, you should work with the original values and increase the angle in each frame. This makes sure that each value only participated in a single rotation computation.
For fixing both problems, keep the original coordinates somewhere in your code, I call them coords, and rewrite the code such that you take that array as input (keep newCoords as the output). Increase the rotation angle in each frame to achieve a rotation animation.
This fixes both problems because you get rid of that chain and also you have different arrays for input and output in your rotation function.
Pseudo-code:
// initial:
angle = 0.0;
coords = (initial coordinates)
// per frame:
angle += 0.5;
newCoords = rotate(coords, angle);
draw(newCoords);
Also, please note that 0.5 is a large angle if you want to rotate by that angle frame by frame. The math functions expect angle in radians (not degrees), so you might want to use a lower value depending on what you want to visualize in particular.
You might wonder why I reuse the old angle in each frame, as according to the above mentioned problem 2., it should introduce numerical problems, since it's also a chain of computations. That's not a problem with the rotation angle, as a simple summation doesn't show such bad numerical errors you experience with applying rotations. Yet it has some problems, but they only show up at very long running times when the angle reaches some billions. The reason why such a summation in general is not that bad is because you're changing the variable in the same direction in each frame as well as a slightly off rotation angle isn't noticed very much by the user.
Found plenty of questions that were similar, but nothing that answers my own problem. It's probably something really bloody simple, but it's late and I can't fathom it. I've got an android game I'm working on, where you touch the screen and it 'fires' a sprite in that direction. I've got most of the code working, however, after the sprite fires and moves off, it gets to the touch point and then just wiggles. I would like it to carry on along that angle and eventually bounce around...
Here's my code (well the bits that matter):
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
int len = touchEvents.size();
for(int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if(event.type == TouchEvent.TOUCH_UP) {
touchPoint.set(event.x, event.y);
guiCam.touchToWorld(touchPoint);
}
}
//Log.d("PANDAM", touchPoint.x + "|" + touchPoint.y);
float speed = 112f;
double theta = 180.0 / Math.PI * Math.atan2(panda_y - touchPoint.y, panda_x - touchPoint.x);
Log.d("PANDAM", " > "+theta+" < ");
movePanda(theta, speed, deltaTime);
And the "movePanda" method:
private void movePanda(double angle, float speed, float deltaTime)
{
panda_x += speed * Math.cos(angle)*deltaTime;
panda_y += speed * Math.sin(angle)*deltaTime;
}
My question is, how do I get the panda to carry on along the touch vector and not spaz out when it reaches the original touch point?
You seem to be recalculating the angle each step of the animation, but you actually need to remember what the angle was when you first started moving. As you pass the original touch point, the angle changes to point the other direction, so if you reclcalculate it every animation step, it will change and eventually point the other way.
I am trying to write a simple physics simulation where balls with varying radii and masses bounce around in a perfectly elastic and frictionless environment. I wrote my own code following this resource: http://www.vobarian.com/collisions/2dcollisions2.pdf and I also tested the code from here: Ball to Ball Collision - Detection and Handling
QUESTION EDITED
With the help of Rick Goldstein and Ralph, I have gotten my code to work (there was a typo..). Thanks so much for you help. However I am still confused as to why the other algorithm isn't working for me. The balls bounce off in the correct directions, but the total energy of the system is never conserved. The velocities get faster and faster until the balls just start blinking in static positions on the screen. I actually want to use this code in my program, because it is a lot more concise than the one I wrote.
Here is the functional algorithm that I wrote (although I did take the first bit from that other source). Its in a Bubble class:
public void resolveCollision(Bubble b)
{
// get the minimum translation distance
Vector2 delta = (position.subtract(b.position));
float d = delta.getMagnitude();
// minimum translation distance to push balls apart after intersecting
Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / b.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));
//get the unit normal and unit tanget vectors
Vector2 uN = b.position.subtract(this.position).normalize();
Vector2 uT = new Vector2(-uN.Y, uN.X);
//project ball 1 & 2 's velocities onto the collision axis
float v1n = uN.dot(this.velocity);
float v1t = uT.dot(this.velocity);
float v2n = uN.dot(b.velocity);
float v2t = uT.dot(b.velocity);
//calculate the post collision normal velocities (tangent velocities don't change)
float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);
//convert scalar velocities to vectors
Vector2 postV1N = uN.multiply(v1nPost);
Vector2 postV1T = uT.multiply(v1t);
Vector2 postV2N = uN.multiply(v2nPost);
Vector2 postV2T = uT.multiply(v2t);
//change the balls velocities
this.velocity = postV1N.add(postV1T);
b.velocity = postV2N.add(postV2T);
}
And here is the one that doesn't work
public void resolveCollision(Bubble b)
{
// get the minimum translation distance
Vector2 delta = (position.subtract(b.position));
float d = delta.getMagnitude();
// minimum translation distance to push balls apart after intersecting
Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / b.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));
// impact speed
Vector2 v = (this.velocity.subtract(b.velocity));
float vn = v.dot(mtd.normalize());
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse (1f is the coefficient of restitution)
float i = (-(1.0f + 1f) * vn) / (im1 + im2);
Vector2 impulse = mtd.multiply(i);
// change in momentum
this.velocity = this.velocity.add(impulse.multiply(im1));
b.velocity = b.velocity.subtract(impulse.multiply(im2));
}
Let me know if you find anything. Thanks
Is there a typo in the line that sets v1nPost? Looks like the denominator should be this.mass + b.mass, not this.mass * b.mass.
Also, because you're computing a collision between this and b, are you checking to make sure you're not also doing the same collision between b and this, thus doubling the delta applied to each participating bubble in the collision?
I do a first guess: getMass() return an integer(or int) (and not a float or double)?
If this is true, than you problem is that 1 / getMass() will result in an integer value (and can be only 1 or most time 0)). To fix this replace 1 by 1.0 or 1.0f
Because the general rule is simple:
If you have a math operation (+,-,*,/) the resulting type will be integer if none of the both operants is a floating point data structure (double or float)
Anyway: there could be a second problem, may your calcualtion is not precise enougth. Then you should use double instead of float.
There is a part that looks strange:
The two calculations:
float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);
are symmetric, except the last operation, in the first it is * in the second it is +