For my game i wanted to use trigonometry. As i have initialy searched everything was the same as it was in Actionscript3. But i was wrong. Nothing worked as it should. So after searching the libGDX forum and stachoverflow posts i have "played" with numbers and find solution. Hope it helps someone
How to calculate an angle in libgdx and how to set x and y velocity with trigonometry (code omitted for clarity):
//variables
private Object object;
private float touchX, touchY, angle, xSpeed, ySpeed;
private final int power = 5;
//touch up event
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
touchX = screenX;
touchY = h - screenY; // screenX gives an inverted y position (y == 0 is at the top)
setPosition(touchX, touchY);
}
//set angle and velocity method
public void setPosition(int x, int y){
//example 1 (velocity is calculated without angle):
angle = (float) (Math.atan2(y - object.y, x - object.x) * tdg) - 90.0f;
//at the end there is not always -90.0f. It depends of how the texture (or sth else we
//want to rotate) is rotated in .png file. Play with nuber if -90.0f is not good. Use
//the scale from -360 to 360
xSpeed = (x - bx) / 30;
ySpeed = (y - by) / 30;
//example 2 (velocity with angle):
angle = (float) Math.atan2(y - object.y, x - object.x);
xSpeed = (float) (Math.cos(angle)*power);
ySpeed = (float) (Math.sin(angle)*power);
angle = (angle*180/Math.PI) - 90.0f;
}
Related
So how do i implement the collision detection for an arc of a circle? Will i have to use the Box 2d collision or can i do it some other way using Rectangle or stuff like that?
BTW I hate box2d because i dont understand most of the things in it, so if there is a solution that excludes the box2d, it will be very much appreciated.
The yellow arc keeps on rotating over the black circle. How do i implement collision detection in here?
Please help ! Thanks!
To avoid using Box2D you could define the shape as a polygon and use the polygon.contains(x,y) method or use the Intersector
Below is an example using both:
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Polygon;
public class Test extends ApplicationAdapter implements InputProcessor{
private ShapeRenderer sr;
private Polygon polya;
private boolean isColliding = false;
private Circle mp;
#Override
public void create () {
//define arc as polygon
// the more points used to define the shape will
// increase both required computation and collision precision
polya = new Polygon();
// create vertices
float section = 15f;
float[] newVerts = new float[200];
for(int i = 0; i < 50; i++){
newVerts[i*2] = (float)Math.sin(i/section); //x 0 to 98 even
newVerts[i*2+1] = (float)Math.cos(i/section); //y 1 to 99 odd
newVerts[199-i*2] = (float)Math.cos(i/section); //x 100 to 108
newVerts[198-i*2] = (float)Math.sin(i/section) + 0.2f; //y 101 to 199
}
polya.setVertices(newVerts);
polya.scale(50);
polya.setOrigin(1, 1);
polya.rotate(60);
//define circle to act as point for checking intersections
mp = new Circle(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2,4);
// setup batchers
sr = new ShapeRenderer();
sr.setAutoShapeType(true);
Gdx.input.setInputProcessor(this);
}
#Override
public void render () {
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// check collision with polygon
isColliding = polya.contains(mp.x,mp.y);
//check collision using Intersector
isColliding = Intersector.isPointInPolygon(polya.getTransformedVertices(),0,polya.getVertices().length,mp.x,mp.y);
sr.begin();
sr.setColor(Color.WHITE);
if(isColliding){
sr.setColor(Color.RED);
}
sr.polygon(polya.getTransformedVertices());
sr.circle(mp.x,mp.y,mp.radius);
sr.end();
}
#Override
public void dispose () {
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
int newy = Gdx.graphics.getHeight() - screenY;
polya.setPosition(screenX, newy);
return false;
}
(... removed unused input processor methods for clarity ...)
}
In my case, the arc was in motion and I needed to calculate its collision, so I updated the polygon along with the rendering. Essentially, I got the vertices in the same way that LibGDX renders an arc.
On the left you can see what the arcs I'm drawing look like. On the right you can see what the polygons would look like calculated from the shape of their corresponding arcs if I had to draw them.
Ignore the different colors and count of sections, they are randomly generated.
To achieve this result, I wrote this method:
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Polygon;
import com.badlogic.gdx.math.Vector2;
import java.util.ArrayList;
// ...
public void fillPolygonWithArc(Polygon polygon, float x, float y, float radius, float start, float degrees, int segments) {
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
ArrayList<Vector2> vertices = new ArrayList<>();
vertices.add(new Vector2(x, y));
vertices.add(new Vector2(x + cx, y + cy));
for (int i = 0; i < segments; i++) {
vertices.add(new Vector2(x + cx, y + cy));
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
vertices.add(new Vector2(x + cx, y + cy));
}
vertices.add(new Vector2(x + cx, y + cy));
cx = 0;
cy = 0;
vertices.add(new Vector2(x + cx, y + cy));
polygon.setVertices(new float[vertices.size() * 2 + 4]);
for (int i = 0; i < vertices.size(); i++) {
polygon.setVertex(i, vertices.get(i).x, vertices.get(i).y);
}
}
// ...
How does he work?
It takes as parameters a polygon in which to write the vertices of the
arch and the parameters needed to get the shape of the arch, these are
the same parameters that you pass to the method that draws the arc (shapeRenderer.arc).
And then it calculates the vertices of the arch in the same way as
LibGDX does and fills the polygon with them.
I just looked at the LibGDX source.
Use case:
fillPolygonWithArc(polygon, getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.setColor(color);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.arc(getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.end();
Also, if you want, you can draw a polygon:
fillPolygonWithArc(polygon, getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.setColor(color);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.polygon(polygon.getVertices());
shapeRenderer.end();
Ultimately, you can check if some point is inside the polygon you need:
polygon.contains(new Vector2(4, 20));
I have a kinematic body with gravity 0 which I want to move from a specific point to a specific point in my world coordinates. I've tried to adjust the code from here
to the one below. But the body stays still and doesn't move?
#Override
public void act(float delta) {
super.act(delta);
//Target position in world coordinates
Vector2 targetPosition = new Vector2(4.5142856f, -4.228572f);
//target speed
float targetSpeed = 1f;
//direction
Vector2 direction = targetPosition.sub(body.getPosition());
//distance
float distanceToTravel = direction.nor().len2();
// For most of the movement, the target speed is ok
float speedToUse = targetSpeed;
float distancePerTimestep = speedToUse / 60.0f;
if ( distancePerTimestep > distanceToTravel )
speedToUse *= ( distanceToTravel / distancePerTimestep );
Vector2 desiredVelocity = direction.scl(speedToUse);
Vector2 changeInVelocity = desiredVelocity.sub(body.getLinearVelocity());
Vector2 force = new Vector2(changeInVelocity.scl(body.getMass() * 60.0f));
System.out.println(force);
body.applyForce(force, body.getWorldCenter(), true);
}
Ok I figured it out. The method below will return the correct velocity so that the body can reach the target point.
public Vector2 calculateVelocity(Vector2 target) {
Vector2 direction = new Vector2(target.x - body.getPosition().x, target.y - body.getPosition().y ).nor();
float speed = Constants.enemySpeed;
return new Vector2( speed * direction.x, speed * direction.y );
}
I'd like to know if there is a java way to, given a polygon, draw another one at a given distance and with the same center.
I tried AffineTransform but don't really know how it Works.
Thank you.
You need to translate your polygon by half its centroid width and height. I have included the code that comes from http://paulbourke.net/geometry/polygonmesh/PolygonUtilities.java to calculate the centroid of a polygon.
public void drawPolygon(){
Graphics2D g2 = bufferedImage.createGraphics();
Polygon poly=new Polygon();
poly.addPoint(100, 100);
poly.addPoint(200, 100);
poly.addPoint(200, 200);
poly.addPoint(150, 250);
poly.addPoint(100, 200);
poly.addPoint(100, 100);
g2.setColor(Color.blue);
g2.fillPolygon(poly);
g2.setColor(Color.red);
Point2D.Double []pts=new Point2D.Double[poly.npoints];
for (int i=0;i<poly.npoints;i++){
pts[i]=new Point2D.Double(poly.xpoints[i],poly.ypoints[i]);
}
Point2D centroid=centerOfMass(pts);
g2.translate(-centroid.getX(), -centroid.getY());
g2.scale(2, 2);
g2.drawPolygon(poly);
}
public static double area(Point2D[] polyPoints) {
int i, j, n = polyPoints.length;
double area = 0;
for (i = 0; i < n; i++) {
j = (i + 1) % n;
area += polyPoints[i].getX() * polyPoints[j].getY();
area -= polyPoints[j].getX() * polyPoints[i].getY();
}
area /= 2.0;
return (area);
}
/**
* Function to calculate the center of mass for a given polygon, according
* to the algorithm defined at
* http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
*
* #param polyPoints
* array of points in the polygon
* #return point that is the center of mass
*/
public static Point2D centerOfMass(Point2D[] polyPoints) {
double cx = 0, cy = 0;
double area = area(polyPoints);
// could change this to Point2D.Float if you want to use less memory
Point2D res = new Point2D.Double();
int i, j, n = polyPoints.length;
double factor = 0;
for (i = 0; i < n; i++) {
j = (i + 1) % n;
factor = (polyPoints[i].getX() * polyPoints[j].getY()
- polyPoints[j].getX() * polyPoints[i].getY());
cx += (polyPoints[i].getX() + polyPoints[j].getX()) * factor;
cy += (polyPoints[i].getY() + polyPoints[j].getY()) * factor;
}
area *= 6.0f;
factor = 1 / area;
cx *= factor;
cy *= factor;
res.setLocation(cx, cy);
return res;
}
Another way of doing this, common in the GIS world, is to buffer a polygon. There is a library called Java Topology Suite that will provide this functionality, although it might be harder to figure out what the scale factor is.
There are some very interesting discussions about polygon growing in this post: An algorithm for inflating/deflating (offsetting, buffering) polygons
I want to create a simple missile object, which moves at a set speed and rotates towards a specific target at a given rotation speed. However, I'm having trouble figuring out the math of it. This is my code so far:
private function enterFrame(e:Event):void {
// Rotate the missile towards the target.
var targetAngle:Number = getAngle(target.x, target.y, x, y);
if (targetAngle < 0) {
targetAngle += 360;
}
if (targetAngle - turnSpeed > rotation) {
rotation += turnSpeed;
} else if (targetAngle + turnSpeed < rotation) {
rotation -= turnSpeed;
} else {
rotation = targetAngle;
}
// Set the target point to move to based on angle and speed.
var newX:Number = x + Math.sin(degreesToRadians(rotation)) * speed;
var newY:Number = y + Math.cos(degreesToRadians(rotation)) * speed;
// Move to new location
x = newX;
y = newY;
}
private function getAngle (x1:Number, y1:Number, x2:Number, y2:Number):Number {
var dx:Number = x2 - x1;
var dy:Number = y2 - y1;
return (Math.atan2(dy,dx) * 180) / Math.PI;
}
private function degreesToRadians(degrees:Number):Number {
return degrees * Math.PI / 180;
}
I've been trying to debug it using trace and such, but I can't seem to figure out where the problem is, most likely because there are many problems and I can't tell if I've fixed one because the others are masking it. I suspect that the issue(s) lie somewhere in the rotation calculations, since I'm pretty sure that the movement part is working as it should, but I can't say for sure.
At any rate, whatever I do, the missiles always seem to fly off in random directions, sometimes tracking towards straight up, or straight down, or just looping around after nothing in particular.
I'm building a particles systems, one of the features I'd like to add is a "target" feature. What I want to be able to do is set an X,Y target for each particle and make it go there, not in a straight line though (duh), but considering all other motion effects being applied on the particle.
The relevant parameters my particles have:
posx, posy : inits with arbitrary values. On each tick speedx and speedy are added to posx and posy respectively
speedx, speedy : inits with arbitrary values. On each tick accelx and accely are added to speedx speedy respectively if any)
accelx, accely : inits with arbitrary values. With current implementation stays constant through the lifespan of the particle.
life : starts with an arbitrary value, and 1 is reduced with each tick of the system.
What I want to achieve is the particle reaching the target X,Y on it's last life tick, while starting with it's original values (speeds and accelerations) so the motion towards the target will look "smooth". I was thinking of accelerating it in the direction of the target, while recalculating the needed acceleration force on each tick. That doesn't feel right though, would love to hear some suggestions.
For a "smooth" motion, you either keep the speed constant, or the acceleration constant, or the jerk constant. That depends on what you call "smooth" and what you call "boring". Let's keep the acceleration constant.
From a physics point of view, you have this constraint
targetx - posx = speedx*life + 1/2accelx * life * life
targety - posy = speedy*life + 1/2accely * life * life
Because distance traveled is v*t+1/2at^2. Solving for the unknown acceleration gives
accelx = (targetx - posx - speedx*life) / (1/2 * life * life)
accely = (targety - posy - speedy*life) / (1/2 * life * life)
(For this to work speedy must be in the same unit as time, for example "pixels per tick" and life is a number of "ticks". )
Since you use euler integration, this will not bring the particle exactly on the target. But I doubt it'll be a real issue.
Works like a charm:
Another picture, this time with constant jerk
jerkx = 6.0f*(targetx-x - speedx*life - 0.5f*accelx*life*life)/(life*life*life)
Looks like there is another bend in the curve...
Java code
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class TargetTest extends JPanel {
List<Particle> particles = new ArrayList<Particle>();
float tx, ty; // target position
public TargetTest() {
tx = 400;
ty = 400;
for (int i = 0; i < 50; i++)
particles.add(new Particle(tx / 2 + (float) (tx * Math.random()), ty / 2
+ (float) (ty * Math.random())));
this.setPreferredSize(new Dimension((int) tx * 2, (int) ty * 2));
}
#Override
protected void paintComponent(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setColor(Color.black);
// comment next line to draw curves
g.fillRect(0, 0, getSize().width, getSize().height);
for (Particle p : particles) {
p.update();
p.draw(g);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Particle tracking");
final TargetTest world = new TargetTest();
f.add(world);
// 1 tick every 50 msec
new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
world.repaint();
}
}).start();
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
class Particle {
float x, y;// position
float vx, vy;// speed
float ax, ay;// acceleration
float jx, jy;// jerk
int life; // life
float lastx, lasty;// previous position, needed to draw lines
int maxlife; // maxlife, needed for color
public Particle(float x, float y) {
this.x = x;
this.y = y;
// pick a random direction to go to
double angle = 2 * Math.PI * Math.random();
setVelocity(angle, 2);// 2 pixels per tick = 2 pixels per 50 msec = 40
// pixels per second
// the acceleration direction 'should' be close to being perpendicular to
// the speed,
// makes it look interesting, try commenting it if you don't believe me ;)
if (Math.random() < 0.5)
angle -= Math.PI / 2;
else
angle += Math.PI / 2;
// add some randomness
angle += (Math.random() - 0.5) * Math.PI / 10;
setAcceleration(angle, 0.1);
life = (int) (100 + Math.random() * 100);
maxlife = life;
lastx = x;
lasty = y;
}
public void setVelocity(double angle, double speed) {
vx = (float) (Math.cos(angle) * speed);
vy = (float) (Math.sin(angle) * speed);
}
public void setAcceleration(double angle, double speed) {
ax = (float) (Math.cos(angle) * speed);
ay = (float) (Math.sin(angle) * speed);
}
#SuppressWarnings("unused")
private void calcAcceleration(float tx, float ty) {
ax = 2 * (tx - x - vx * life) / (life * life);
ay = 2 * (ty - y - vy * life) / (life * life);
}
private void calcJerk(float tx, float ty) {
jx = 6.0f * (tx - x - vx * life - 0.5f * ax * life * life)
/ (life * life * life);
jy = 6.0f * (ty - y - vy * life - 0.5f * ay * life * life)
/ (life * life * life);
}
public void update() {
lastx = x;
lasty = y;
if (--life <= 0)
return;
// calculate jerk
calcJerk(tx, ty);
// or uncomment and calculate the acceleration instead
// calcAcceleration(tx,ty);
ax += jx;
ay += jy;// increase acceleration
vx += ax;
vy += ay;// increase speed
x += vx;
y += vy;// increase position
}
public void draw(Graphics2D g) {
if (life < 0)
return;
g.setColor(new Color(255 - 255 * life / maxlife,
255 * life / maxlife,0));
g.drawLine((int) x, (int) y, (int) lastx, (int) lasty);
}
}
}
You could consider that your particule is initially "applied" a force (Fv) which corresponds to the inertia it has from its initial velocity. Then you apply an attraction force (Fa) that is proportionnal to the distance to the target. You can then sum those forces, and given a particle weight, you can deduce acceleration to consider at time t.
Fa(t) = (Constant / distanceToTarget(t))* [direction to target]
Fv(t) = [initialForce] * dampening(t)
a(t) = (Fa(t) + Fv(t)) / mass
Then you can compute v(t) from v(t-1) and a(t) as usual
Edit: I forgot the life of the particle can directly be computed from the distance to the target (for instance: life = distance / initialDistance will go from 1 at start and approch 0 near the target)
Edit: You could think of this as a kind of magnet. See wikipedia for the force formula.
one kind of movement you can use is the uniform acceleration http://en.wikipedia.org/wiki/Acceleration#Uniform_acceleration
Your particles will make a smoth move towards the target and hit it with rather high velocity
For meeting your stated criteria, do the following:
calculate the distance from the target, the particle will have at the end of it's life time, assuming the speed doesn't change from now on.
this distance put in this equation: http://upload.wikimedia.org/math/6/2/9/6295e1819e6bfe1101506caa4b4ec706.png and solve it for a
use this as your acceleration
Do this seperately for x and y