Collision detection for an arc of a circle - libgdx

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));

Related

How to achieve the following effect with libGDX?

I'm developping a game with libGDX. I have a question: Know the initial coordinates and target coordinates, as the picture shows, how to achieve the parabolic effect of the bullet ? to achieve the operation of shells . Who can teach me ? or tell me some tutorial. Tks
picture
You need to add some physics to your app (ex. Box2d). Then you 'throw' canon ball with some velocity and some direction/angle.
Physics engine do rest for you.
Here you have tutorial for box2d: https://www.youtube.com/watch?v=vXovY2KTing
Very very basic example for throw something without box2d. For your example you need to calculate right 'power' for target position.
public class SampleApp extends ApplicationAdapter
{
Sprite sprite;
Vector2 velocity = new Vector2(0, 0);
Vector2 terminateVelocity = new Vector2(2000, 2000);
Vector2 friction = new Vector2(200, 300);
Vector2 position = new Vector2(0, 0);
Vector2 launchPower = new Vector2(0, 0);
boolean shotNow;
#Override
public void render()
{
update(Gdx.graphics.getDeltaTime());
// ...
// here render your stuff
}
public void shot(float power)
{
// Calculate x launch power
launchPower.x = ((power - sprite.getX() + sprite.getWidth()*0.5f) / 2f) + velocity.x;
// We want to end our fly at ground
launchPower.y = ((0 - sprite.getY()) / 2f) + velocity.y;
// Setup start position
position.x = sprite.getX();
position.y = sprite.getY();
// Add some acc to velocity
velocity.add(launchPower);
shotNow = true;
}
public void update(float dt)
{
if (Gdx.input.justTouched()) {
shot(900);
}
// Very basic sprite movement.
// For best results you should implement more physics (acceleration etc.)
if (shotNow && position.y > 0) {
// Friction/gravity
velocity.x = MathUtils.clamp(velocity.x - friction.x * dt, -terminateVelocity.x, terminateVelocity.x);
velocity.y = MathUtils.clamp(velocity.y - friction.y * dt, -terminateVelocity.y, terminateVelocity.y);
position.add(velocity.x * dt, velocity.y * dt);
sprite.setPosition(position.x, position.y);
}
}
}

move body to specific point in world coordinates at a constant speed

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 );
}

Calculate a trajectory for an object, when given an angle and a velocity in flash

I am trying to launch a cannonball from a cannon and have it follow a realistic path. The angle of fire changes depending on the orientation of the cannon (automatically orientates to mouse pointer). So what I'm trying to figure out, is how to move a cannonball along a parabolic path, when given an angle, and a set velocity.
I've read that this can be done without complicated trigonometry (never listened to it in highschool), and can be calculated simply by adding gravity to the yVelocity every tick. However, at this moment, I don't know how to calculate the initial yVelocity (again, depending on cannon orientation).
You can see the current animation here: http://kate.ict.op.ac.nz/~welfajw1/portfolio/videos/task3-assignment2.swf
This is all done in AS3, and the code I have is as follows:
Main timeline code:
import flash.display.*;
import flash.events.*;
import flash.geom.*;
var cannonball:ball_mc;
var angleDegree;
myCannon.addEventListener(Event.ENTER_FRAME, cannonEnterFrame);
function cannonEnterFrame(pEvt)
{
var mc = myCannon;
var mg = myCannon.myGun;
//find angle for orientation
var angleRadian = Math.atan2(mouseY - mc.y, mouseX - mc.x);
//convert to degrees
angleDegree = angleRadian * 180 / Math.PI;
//limit rotation
if(angleDegree > -63 && angleDegree < 20)
mg.rotation = angleDegree;
}
stage.addEventListener(Event.ENTER_FRAME, stageRefresh);
function stageRefresh(pEvt)
{
if (cannonball)
{
//move every "tick"
cannonball.move();
}
}
stage.addEventListener(MouseEvent.CLICK, mouseClicked);
function mouseClicked(pEvt)
{
//starting position of the ball
cannonball = new ball_mc(100, 475);
//SEND IN INITIAL x, y VELOCITIES
cannonball.fire(20, angleDegree);
//add to stage
stage.addChild(cannonball);
}
ball_mc code:
package
{
import flash.display.MovieClip;
import flash.sensors.Accelerometer;
import flashx.textLayout.formats.Float;
public class ball_mc extends MovieClip
{
//constant gravity
public static const g:Number = 2;
//starting velocities
private var ux:Number;
private var uy:Number;
public function ball_mc(startX:int, startY:int)
{
x = startX;
y = startY;
}
public function fire(vx:Number, vy:Number):void
{
ux = vx;
uy = vy;
}
public function move():void
{
//distance moved in x dir
var sx:Number = ux;
//new velocity in y dir
var vy:Number = uy + g;
//distance moved in y dir
var sy:Number = uy + g/2;
//apply movement
x += sx;
y += sy;
//save new y velocity
uy = vy;
}
}
}
You need a little bit of physics.
Initial speed must be calculated by using some criteria that you add on your own. One example is to calculate initial speed by using the distance between the mouse and the cannon, at the time the mouse is pressed. If the distance is greater the projectile will have a bigger speed, and if the distance is smaller the projectile will have smaller speed.
The you add an Event Listener with type ENTER_FRAME.
I guess it's 2 dimensional animation so you have to find the current x and y at any point in time.
Here's a little bit of code:
var TimeperFrame:Number = 1/fps //fps is not a constant, here you should add a number, a value that you previously added in fla. document properties. I usualy use 60 fps
var Time:Number = 0;
addEventListener(ENTER_FRAME, movingCannonBall);
function movingCannonBall(e:Event):void
{
Time += TimeperFrame;
}
Now here's the equitation for trajectory of projectile.
x = xo + vxo·t
y = yo + vyo·t - 0.5·g·t^2
yo = initial height of your cannon ball
vyo = initial y velocity; vyo = vo·sin θ
t = time passed, we conrol that by upper code
g = acceleration (9,81 m/s^2) at Earth's surface
xo = initial distance for the start
vxo = initial x velocity; vxo = vo·cos θ
Now in the upper code we add these equitations and it should look like this:
var TimeperFrame:Number = 1/fps
var Time:Number = 0;
var initx: Number = cannonball.x;
var inity: Number = cannonball.y;
var initVelocity: Number = (you define initial Velocity by your criteria)
var G: Number = 9.81;
addEventListener(ENTER_FRAME, movingCannonBall);
function movingCannonBall(e:Event):void
{
Time += TimeperFrame;
cannonball.x = initx + Math.cos(angle) * initVelocity * Time;
cannonball.y = inity + Math.sin(angle) * initVelocity * Time - G * Time * Time * 0.5
}
This should work. I have use this code many times and it's effiecient and also it's simple.

Dealing with twip precision limit placed on DisplayObject positioning

I'm working on a project to render xps content in flash, and am running into the twip (1/20 of a unit) precision limit in flash. The twip limit is mentioned in the swf file format, but in the flash as3 documentation it's only mentioned in PrintJob.addPage method. However, when setting the DisplayObject x and y properties, any precision less than 0.05 is rounded. Regardless of any scaling. The code below demonstrates this issue.
package
{
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.GraphicsPathCommand;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageScaleMode;
public class TWIPTest extends Sprite
{
// can change behaviour by switching between createPoint and drawPoint
public function TWIPTest()
{
this.stage.scaleMode = StageScaleMode.NO_SCALE;
// scale our unit square so we can see what is happening
scaleX = 400; scaleY = 400;
// draw grid
var grid : Sprite = new Sprite();
addChild(grid);
grid.graphics.lineStyle(TWIP, 0x888888);
drawGrid(1 / TWIP, 1 / TWIP, TWIP, TWIP, grid);
// center of unit square
var cx : Number = 0.5;
var cy : Number = 0.5;
var shape : Shape;
// GREEN in middle of unit square
this.addChild(createPoint(cx, cy, 0x00FF00));
//drawPoint(cx, cy, 0x00FF00, this.graphics);
// BLUE one TWIP away from GREEN
this.addChild(createPoint(cx + TWIP, cy + TWIP, 0x0000FF));
//drawPoint(cx + TWIP, cy + TWIP, 0x0000FF, this.graphics);
// RED half a TWIP away from GREEN (this does not work....)
this.addChild(createPoint(cx + (TWIP / 2), cy + (TWIP / 2), 0xFF0000, 0.5));
//drawPoint(cx + (TWIP / 2), cy + (TWIP / 2), 0xFF0000, this.graphics, 0.5);
// now insert new container to work around limit encontered with RED point
var container : Sprite = new Sprite();
this.addChild(container);
container.scaleX = 0.5; container.scaleY = 0.5;
container.addChild(createPoint(2 * cx + TWIP, 2 * cy + TWIP, 0xFF00FF, 1.0, 2 * TWIP));
//drawPoint(cx + (TWIP / 2), cy + (TWIP / 2), 0xFF00FF, container.graphics);
}
static private function createPoint(x:Number, y:Number,color:uint,alpha:Number=1.0,radius:Number=0.05):Shape
{
var shape : Shape = new Shape();
shape.x = x; shape.y = y;
shape.graphics.beginFill(color,alpha);
shape.graphics.drawCircle(0, 0, radius);
shape.graphics.endFill();
return shape;
}
static private function drawPoint(x:Number, y:Number,color:uint,target:Graphics,alpha:Number=1.0,radius:Number=0.05):void
{
target.beginFill(color,alpha);
target.drawCircle(x, y, radius);
target.endFill();
}
// drawGrid from #Feltope
private function drawGrid(numColumns:Number, numRows:Number, cellHeight:Number, cellWidth:Number, grid:Sprite):void
{
for (var col:Number = 0; col &lt numColumns + 1; col++)
{
for (var row:Number = 0; row &lt numRows + 1; row++)
{
grid.graphics.moveTo(col * cellWidth, 0);
grid.graphics.lineTo(col * cellWidth, cellHeight * numRows);
grid.graphics.moveTo(0, row * cellHeight);
grid.graphics.lineTo(cellWidth * numColumns, row * cellHeight);
}
}
}
static private const TWIP : Number = 0.05;
}
}
This posting also mentions this issue.
The problem is that in parsing xps files this can happen anytime, and many times, for example
&ltCanvas RenderTransform="96.201126,0,0,-95.787476,713.62598,207.05859"&gt
&ltPath Data="..." RenderTransform="0.010394889,0,0,-0.010439778,-7.4180626,2.1616458"&gt
Notice the dx in the Path element, which seems trivial, but the parent Canvas (and other parents above this) scale it up so the rounding of dx to 0 or 0.05 is very noticeable.
I could add Sprite containers whenever this happens, as in the code above, but that's going to bloat memory and slow down rendering.
My question (finally), has anyone dealt with this issue? Any ideas on a better way of handling this limit? Workarounds? Any help appreciated. cheers
what is the biggest problem here? How it looks on screen or that after parsing the precision is lost? You can't do with rendering but you could do modified DisplayObject that will store for example position then reading it will contain the precision kept. or am I missing the point?:)
Edit:
Following is an example of custom display objects (Shape and Sprite)
import flash.display.Shape;
import flash.display.Sprite;
internal class MySprite extends Sprite
{
protected var m_nX:Number;
protected var m_nY:Number;
override public function get x():Number
{
return m_nX;
}
override public function set x(value:Number):void
{
m_nX = value;
super.x = m_nX;
}
override public function get y():Number
{
return m_nY;
}
override public function set y(value:Number):void
{
m_nY = value;
super.y = m_nY;
}
}
internal class MyShape extends Shape
{
protected var m_nX:Number;
protected var m_nY:Number;
override public function get x():Number
{
return m_nX;
}
override public function set x(value:Number):void
{
m_nX = value;
super.x = m_nX;
}
override public function get y():Number
{
return m_nY;
}
override public function set y(value:Number):void
{
m_nY = value;
super.y = m_nY;
}
}
Add this to your example and replace any instantiation of Shape and use MyShape, same for Sprite, replace it by MySprite. There will be no visual difference but the x and y of them will return precise values.
This is a sample test for precision keeping:
addChild(createPoint(0.51000005, 0.510000049, 0x800000, 1, TWIP));
var disp :DisplayObject = getChildAt(numChildren - 1);
trace(disp.x, disp.y);
will trace 0.51000005, 0.510000049 but above test added to your example without MySprite and MyShape custom DisplayObjects will return 0.5 0.5.

Algorithm for particles targeting

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