View Full Version : Java 2d physics
Stereo
2009-02-05, 08:23 PM
http://img80.imageshack.us/img80/2843/springmotion4wr8.jpg
I've been putting this together just for fun, but I'm not completely happy with how it works.
The balls are point masses, the lines act like ideal springs (F = -xk) and I'd got a bit of a workaround for the damping coefficient so I'm kinda looking for physics / programming advice.
Currently the damping pseudocode looks kinda like this
get velocity of 2 end points
project both onto the direction of the spring
use that component to find a weighted average
end1 = c*(end2-end1) type thing
subtract this from each end velocity so they get closer to each other
It seems to work out pretty well (as seen above) I'm just not sure how physically accurate it is.
I know the damping on a spring drops velocity by a constant, but that's taking 1 end to be fixed, which I can't really do with multiple linked springs.
Also I'm in need of an efficient intersection algorithm (to test when 2 balls collide) so any advice there would be nice too.
And if there's some way to somehow render these to a seperate layer instead of the background so it doesn't keep every iteration that would be helpful too. Right now (aside from screenshot above, where I disabled it to show how it animates) I'm overwriting the entire panel with a white rectangle between every iteration and this is kinda slow.
I don't really know anything about the physics you need help with, or graphics in Java, but is what you're using for graphics intended to be used for animation? I'm pretty sure clearing the screen to a background color and drawing your stuff on every frame is the normal way of doing things, so I don't think that's the cause of the slowness. I wrote a Winforms app for designing particle emitter effects for the game that is my senior project, and that's how the effect preview gets drawn (using a form control for displaying XNA graphics).
Another possible cause of speed loss is the physics calculations, but you don't seem to be doing anything computation-intensive.
Finally, how is your drawing code getting called? Are you just in a loop doing it over and over, or is it controlled somehow?
Stereo
2009-02-06, 09:04 PM
Using a Timer class to call it every X milliseconds, I vary between about 5-50ms per frame because the redrawing starts to lag with shorter times, but it is more accurate.
I'm not sure if the thing is meant for animation, it's just the general JFrame. Tutorials online kinda indicate it would clear itself on each call to repaint() but mine doesn't except when I resize the window :x
It does look kinda neat this way, though. Especially using multiple springs ilke that.
http://img6.imageshack.us/img6/2828/springmotion10me3.png
Yeah, that definitely isn't intended for animation and that would be your problem. To get better performance, you could use a game framework and just put your physics code in its Update() method and drawing code in its Draw() method or whatever the framework calls them.
Stereo
2009-02-07, 11:57 AM
Rebooted my computer and it runs a lot smoother so I'm not worrying about it :P
Trying to add collisions between the particles now. Looks ok, doesn't act quite like real life.
DeadHead
2009-02-08, 06:42 PM
Just to confirm, clearing the screen every frame is the normal way of animation. Its how everything else works, including 3d graphics libraries like OpenGl, etc.
For detecting the collision between two spheres (that part's very easy and I'm sure you've figured it out already). Just take the distance between the spheres and if it is less then the two radii combined, then they are colliding.
For the response after the collision, an easy way to do it is:
Find the direction between the centre of the two particles.
The velocities perpindicular to that direction do not change.
The momentum in that direction of the two particles react with each other as if it were a 1d collision.
That will give a pefectly elastic collision.
If this isn't specific enough, I can go into more detail.
Stereo
2009-02-09, 08:30 AM
Got that far, but I can't seem to get the 1d collision to act realistically.
double rate = (dx*vx + dy*vy)/(Math.pow(dx,2)+Math.pow(dy,2));
double orate = (dx*ovx + dy*ovy)/(Math.pow(dx,2)+Math.pow(dy,2));
// average
double arate = (rate+orate)/2;
// mass weighted
double rm = m*(rate-arate);
double orm = om*(orate-arate);
// elasticity
double a = 0.1;
// new vector other's v avg to balance
double ir = a*(orm-rm)/(m)+arate - rate;
double oir = a*(rm-orm)/(om)+arate - orate;
vx += ir*dx;
vy += ir*dy;
ovx += oir*dx;
ovy += oir*dy;
First I calculate the projection onto the vector (dx,dy) - the difference in centre - for the 2 particles (v, ov). Then subtract the average speed (I'm not sure this is done properly but I went with what works, doing this in other order led to problems) then multiply each by weight(m) to get momentum, then swap those, then find the overall change.
I think the main trouble I have is that when 2 particles are traveling the same way, with a smaller one following, it'll keep bouncing off the surface of the larger and then swinging back (due to gravity/pendulum) but I've never really tested these irl so, I don't know if that's correct.
http://img7.imageshack.us/img7/8060/springmotion11zd4.png
Every frame where a collision is detected is coloured red, you can see they only make contact about every 10. In the other direction (big following small) they stay closer together, with contact every 2nd frame.
Normally looks like this, I just disable the overwriting to make the animation paths clear.
http://img228.imageshack.us/img228/2586/springmotion12ie7.png
I'd also like to add rotational speed via these collisions, I think it would just be radius*angular v = surface velocity, combine that and the relative motion of the 2 to get a difference in surface speed, and use some sort of friction model to speed up/slow down the rotation speed.
DeadHead
2009-02-10, 01:40 AM
hmm.. I don't believe you are supposed to take the average of the velocities at all.
What I would do is use the Law of Conservation of Momentum and the Law of Conservation of Energy as follows:
//get projection onto vector between the two spheres
double vel = (dx*vx + dy*vy)/(Math.pow(dx,2)+Math.pow(dy,2));
double ovel = (dx*ovx + dy*ovy)/(Math.pow(dx,2)+Math.pow(dy,2));
//get projection onto vecto perpendicular to the spheres (other part of the velocity)
double comp = (dy*vx - dx*vy)/(Math.pow(dx,2)+Math.pow(dy,2));
double ocomp = (dy*ovx - dx*ovy)/(Math.pow(dx,2)+Math.pow(dy,2));
// using solved equations from momentum and KE
double fvel = ((m - om)/(m + om))*vel + ((2*om)/(m + om))*ovel;
double fovel = ((2*m)/(m + om))*vel + ((om - m)/(m + om))*ovel;
Then you project comp and fvel back onto vx and vy, and ocomp and fovel onto ovx and ovy.
There's probably a better way to do the projections without having to solve for (o)comp, but its way too late/early right now to figure it out.
Hope this works.
As for rotational motion, if you use that equation, things work perfectly if you assume that the object will always be perfectly rotating. Thing is, when two spheres collide, their rotations would not be perfectly in conjunction with their movement. I'd know how to solve for this on a surface, but I'm not quite sure how that'd work in the air.
Stereo
2009-02-10, 08:25 AM
There's probably a better way to do the projections without having to solve for (o)comp, but its way too late/early right now to figure it out.
Basically what I did for that is that if you split the original V into 2 components (in the direction of the collision and other), subtract the (o)vel from the original, then you get the component in the other direction.
I thought about subtracting the average and you're right it's not helpful.
1 option (to make solving easier) would be subtract the speed of the 1st point from both:
ovel = ovel - vel;
vel = 0;
This makes the equations simpler since all the input motion is done by 1 sphere. If it was perfectly inelastic that leads to fv = (om/(m+om))*ovel; if it is perfectly elastic fv = 2*(om/(m+om))*ovel; fov = ((om-m)/(m+om))*ovel;
Compromise these (for partially elastic) would be something like that, for a constant a: fv = (1+a)*(om/(m+om))*ovel; fov = ((om-a*m)/(m+om))*ovel;
With a = 0.0 it is inelastic, with a = 1.0 it is elastic.
Then shift the frame of reference back by adding vel to both.
However the original velocities already have vel & ovel in them, so add the negative of that to get the velocity to add to the original to get the new one. Same thing as taking V - vel = perpendicular speed.
So
fv = (1+a)*(om/(m+om))*(ovel-vel) + (vel - vel); // 0
fov = ((om-a*m)/(m+om))*(ovel-vel) + vel - ovel;
x += dx*fv;
y += dy*fv;
Thanks for the help.
As for the rotation thing, maybe I'll skip it. In the long run most of the sphere collisions will be with non-moving surfaces (I am intending to add those next, after which I will add collisions to them)
I think I can do it in a sort of sequence, using a few numbers
1) radius of circle
2) "radius" of line (maximum distance from center)
3) centres of both
a) find the total distance between the centers
b) if distance > radius1+radius2, they don't collide
c) if distance^2 > radius1^2+radius2^2, they may collide at an end point (check if end points are touching circle)
d) if distance is shorter, the circle may be tangent - check perpendicular distance to line
In any case since all the colliding lines will be fixed (for now anyway) it makes working stuff out much easier.
Haven't had a chance to code since I'm busy with homework+study but maybe on Wednesday-Thursday I'll do something :P
edit: Fixed circle collisions, added initial part of line collisions (hitting the ends of a line)
http://img155.imageshack.us/img155/3113/springmotion13rm0.png
Powered by vBulletin® Version 4.1.10 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.