Physics circle collisions popping and sliding against bounds - java

In Java, I'm writing a mobile app for Android to interact with some dynamic balls with some classes I wrote myself. Gravity is determined on the tilt of the phone.
I noticed when I have a bunch of balls bunched up in a corner that some of them will begin to jitter, or sometimes slide while colliding with other balls. Could this be because I'm executing steps in the wrong order?
Right now I have a single loop going through each ball to:
Sim an iteration
Check collisions with other balls
Check collisions against scene bounds
I should add that I have friction with the bounds and when a ball to ball collision occurs, just to lose energy.
Here's a portion of code of how collision is being handled:
// Sim an iteration
for (Ball ball : balls) {
ball.gravity.set(gravity.x, gravity.y);
if (ball.active) {
ball.sim();
// Collide against other balls
for (Ball otherBall : balls) {
if (ball != otherBall) {
double dist = ball.pos.distance(otherBall.pos);
boolean isColliding = dist < ball.radius + otherBall.radius;
if (isColliding) {
// Offset so they aren't touching anymore
MVector dif = otherBall.pos.copy();
dif.sub(ball.pos);
dif.normalize();
double difValue = dist - (ball.radius + otherBall.radius);
dif.mult(difValue);
ball.pos.add(dif);
// Change this velocity
double mag = ball.vel.mag();
MVector newVel = ball.pos.copy();
newVel.sub(otherBall.pos);
newVel.normalize();
newVel.mult(mag * 0.9);
ball.vel = newVel;
// Change other velocity
double otherMag = otherBall.vel.mag();
MVector newOtherVel = otherBall.pos.copy();
newOtherVel.sub(ball.pos);
newOtherVel.normalize();
newOtherVel.mult(otherMag * 0.9);
otherBall.vel = newOtherVel;
}
}
}
}
}

If this is the only code that checks for interactions between balls, then the problem seems pretty clear. There is no way for a ball to rest atop another ball, in equilibrium.
Let's say that you have one ball directly on top of another. When you compute the acceleration of the top ball due to gravity, you should also be doing a collision check like the one you posted, except this time checking for dist <= ball.radius + otherBall.radius. If this is the case, then you should assume a normal force between the balls equal to that of gravity, and negate the component of gravity in line with the vector connecting the two balls' centers. If you fail to do this, then the top ball will accelerate into the bottom one, triggering the collision code you posted, and you'll get the jitters.
Similar logic must be used when a ball is in contact with a scene bound.

Since I've been experimenting with my own Phys2D engine (just for fun), I know you're talking about. (Just in case - you may check my demo here: http://gwt-dynamic-host.appspot.com/ - select "Circle Collisions Demo" there, and corresponding code here: https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar).
The problem is in a nature of iterations and infinite loop of colliding consequences. When e.g. ball is reached the scene corner, it experiences at least 3 vectors of force: impulse of bounce from the wall, impulse of bounce from the floor and impulse of gravity - after you summarize all 3 impulses, reduce it according loosing energy algorithm, you have to have the new vector where your ball should be. But, e.g. this impulse directs it into wall - then you have to recompute the set of vectors again according to all the stuff: energy of bounce, impulses, gravity, etc. Even in case if all these impulses are small, you never get all of them 0, because of precision of doubles and your tolerance comparison constants - that because you have the "jitter" and "sliding" effects.
Actually, most of existing 2D engines have these effects one kind or another: you may see them here: http://brm.io/matter-js/demo/#wreckingBall or here: http://box2d-js.sourceforge.net/index2.html - they actually just make the small impulses to be absorbed faster and stop iterating when the whole system becomes more or less stable, but it is not always possible.
Anyway, I'd just recommend do not reinvent your own wheel unless it is just for your fun - or for your better understanding this stuff.
For last one (JFF) - here is good tutorial: http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331
For real things, I'd recommend to use the existing engines, e.g. Unity (https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d) or Box2d (http://box2d.org/)
Hope this helps.

Iterating through all the balls and changing the balls position for each iteration is probably the cause for the instability, you move a ball left to avoid collision on the right, and then you pushed the ball into another ball on the left, and then the left ball tries to push it back again.
From the top of my head I could recommend trying to sum up all the forces on each ball before doing anything about positioning. And if you iterate from the ball "on top" (furthest away from gravity source/direction) you can probably achieve a stable situation.
Basically, the top ball needs to first calculate forces between itself and the ball(s) under it, plus gravity, then the ball under will know how much force is coming from the top ball, and added with gravity it would also add to the force of which it is pushing the balls under it. When all balls know the forces they're pushed with you can transform that force into motion.

The way you are simulating the physics of the balls is bound to cause instabilities. Your collision resolution tries to separate the balls by projecting one of them in the opposite direction by the collision depth. This may fix the overlap for those two balls but chances are(especially when the balls are stacked) that the ball is now overlapping with another ball.
There are many ways to fix penetration. One of the simplest ways is to add a "bias" or a bit of a push to both bodies to force them to separate over the next couple of frames. This allows that energy to propagate and force all of the bodies apart. Problem is, the bias will often overestimate and cause a bit of a bounce. To fix that problem I'd recommend reading up on sequential impulse.
Making physics look realistic is not as easy as it may seem. Unless you don't mind instabilities I'd recommend spending some time reading up on different techniques or using an engine such as Box2D.

Related

Collision detection between brick and ball (breakout, brick breaker)?

I'm working on a brick breaker game in JavaFX (FXGL). The collision detecting is working like this:
Bricks and players have a x, y position in the game world (placed in LEFT, TOP).
When a collision is detected (this is done by the engine) I use the x, y position to detect where the ball is colliding with the brick to calculate the next direction. The ball direction is created by a velocity vector with (x, y) speed. The collisionLogicSecurityPadding is a small padding which is added since the collision is only detected inside the box. (It's not possible to get the ball and brick exactly at the same x, y coordinates)
if (ball.getX() > levelBrick.getX() - ball.getWidth() + collisionLogicSecurityPadding &&
ball.getX() < levelBrick.getX() + levelBrick.getWidth() - collisionLogicSecurityPadding) {
//velocity.getX(), -velocity.getY()
} else {
//-velocity.getX(), velocity.getY()
}
So I measure if the ball is inside the brick with it x position. If this is the case the collision is TOP or BOTTOM. If not RIGHT or LEFT.
However this is causing the issue when the ball is hitting near the edge it detects wrong. Here a short clip: https://i.imgur.com/U8ybhRl.mp4
The issue is that the x is smaller than the area where it thinks it's TOP or BOTTOM so it's switching the X direction which is causing an issue.
My question here is how to avoid this? Is there any way I can solve the collision that it's working correctly? When I'm looking online the most tutorials are only checking top or bottom collision.
I think you could change the detection of TOP, BOTTOM, LEFT, RIGHT collisions to where the collision happened relative to the ball. Assuming the preservation of momentum you just need to negate the X- or Y-velocity.
In the example above the ball clearly generates a collision TOP and LEFT to his center of mass. Therefore it is impossible to generate a RIGHT collision which would generate the behavior you described. This leaves the Problem, that you do not know yet whether it was a collision on the LEFT or TOP. But since the Vector was pointing to the RIGHT (positive X-Movement), it is impossible to generate a collision on the LEFT. The collision must have happened at the TOP and therefore the Y-velocity needs to be multiplied by -1.
As long as the ball is the only moving object this method cannot generate weird behavior. As soon as you have an Object moving faster then the ball, you need additional checks: An Object hitting the ball on its left, while it is already in a general movement towards right will increase the X-velocity.
As I understood your question it seems to me like your issue is that the red box goes in an incorrect direction after bouncing on an edge.
I think you need to detect collision in three instances.
Top/Bottom
Left/Right
An Edge
If the collision occurs at an edge you need to send it in the same x direction as before with reducing the speed it goes in the direction y. y speed should always be less than initial speed and in the same direction as before.
I think above would solve your issue.

How do I force two Box2D bodies to avoid colliding when they spawn on top of each other?

I'm in the process of creating a sidescrolling action game where you play a wizard that can cast spells. The spells are Box2D bodies that start in the middle of your player (who is also a Box2D body) and go outward in the direction you clicked on the screen.
I have all the collision detection working to where the spells you cast don't collide with each other and they don't collide with you. This works more-or-less flawlessly -- except for one instance. The first spell I cast creates a collision with the player that causes a brief period of physical knockback. The spell's path is not affected otherwise, and I don't notice a major change in the player's position. The only reason I know there is knockback at all is because the camera I have following the player suddenly shakes in that instant (and I've gone through the contact listener to verify that these particular bodies are forming a contact).
This is not the case for subsequent spells that are spawned from the same position, and it doesn't seem to be a problem that is related to the player's move speed or the projectile's cast angle. It may have something to do with how Box2D initializes items, but I couldn't promise that.
Does anyone know how I could fix this?
As weston mentioned, some more code may be needed, but it does sound odd that "the first spell" does this, but subsequent spawnings don't. Do you reuse bodies for subsequent spawns?
In box2d if you create 2 bodies that occupy the same space they will "knockback" from each other so that they DON'T occupy the same space. This is by design, and only happens on creation. I'm sure this is what you're seeing. Why it doesn't happen "afterwards" may be dependent on your code.
Ways around this might be to set some of your fixtures as sensors for a bit (collisions are ignored), or when you create a body, set active=false (again, collisions ignored). By "for a bit" I mean you may have to write some code to move your spell, ignoring collisions, until your spell has "cleared" your wizard. Then remove the sensor or make it active so collisions are back in play.
But that may be overkill, figuring out the subtlety of subsequent "spans" vs. your first one may be a better use of effort.
I managed to figure out where the problem was and how to solve it, but I wasn't able to fight out why it was happening.
I was using an OrthographicCamera to lerp to my player's position.
position.x += (universe.entity_handler.player.parts[0].body.getPosition().x - position.x) * Gdx.graphics.getDeltaTime() *
position.y += (universe.entity_handler.player.parts[0].body.getPosition().y - position.y) * Gdx.graphics.getDeltaTime() * LERP + zoom * viewportHeight / WORLD_PLAYER_Y_SKEW;
And when I fixed this by removing all lerping, the jitter was gone.
position.x = universe.entity_handler.player.parts[0].body.getPosition().x;
position.y = universe.entity_handler.player.parts[0].body.getPosition().y;
I have zero idea why linear interpolation was causing spastic movements like that, but hey - I got it to work. Maybe I'll go back and revisit the problem later.

Java - Breakout physics, ball direction on paddle collision?

I'm creating a Breakout game to familiarize myself with Java.
Currently I've got everything working but I've noticed that the ball seems to take off in the same direction.
I've programmed it so when the ball hits the paddle the Y velocity is reversed. This works, but the ball seems to follow the same route...
How would a make the collision seem more realistic?
When the ball hits the left side of the paddle, I want to redirect it back to the left but I'm not sure at which angle to reflect it. Can anyone provide a formula to help me work out the angle at which I need to direct the ball upon contact with either the left or right side of the paddle?
If the ball hits the paddle from the top, negate Y velocity.
If the ball hits the paddle from the side, negate X velocity.
Reversing the vertical velocity is the correct thing to do for a perfectly elastic collision, which is what you want in a breakout game (the ball keeps it's total velocity after the collision).
The problem of following the same route can be avoided either by randomizing the initial ball position and velocity, or by changing the collision dynamics to be unrealistic. You could either add a small random component to both coordinates (taking care to keep the total velocity the same), or send the ball at a different angle, depending on where it hits the pad (which is what many games of this type do).
To do the later, you need to calculate the absolute position where the ball hits the pad, normalize it (by subtracting the pad position and dividing by the pad length), and map it into a angle range (maybe -80 to 80 degrees). You can then calculate the desired horizontal and vertical velocities using trigonometric functions.
One idea might be to use motion of the paddle to vary the direction a bit. Say, if the paddle is moving to the right when hitting the ball, change the X velocity of the ball to the right a little in addition to reversing the Y direction. That provides a way for the user to actually use some skill to put the right "English" on the ball.
There are two separate problems involved, a design problem and the physics problem. In the end, the physics problem might have the easier solution:
Compute the collision point on the paddle
Compute the instantaneous horizontal velocity pvx of the paddle
Compute the normed outward surface normal (nx,ny) at the impact point. This is the design decision, in the middle part of the paddle one probably wants (nx,ny)=(0,1), while on the left side (nx,ny)=(-1,0) or generally in WNW direction, on the right side correspondingly (nx,ny)=(1,0) or in the general ENE position.
Use the physics formula for a collision with a moving infinitely massive object to compute the new velocity vector (vx,vy):
dot = nx*(vx-pvx)+ny*vy
vx = vx - 2*dot*nx
vy = vy - 2*dot*ny
One may check if the dot product dot is positive to avoid spurious collision computations if paddle and ball do not separate fast enough after collision.

Let an Enemy follow a path with the same speed

I started programming a game in java. I have Enemys and a Player, a basic 2D game, thats to get experience for the first time.
Now i wanted the Enemys to follow a path, which i can draw in to a "level editor".
I have a JPanel, a mouseMoveListener, and on click the Path2D starts saving the mouseMove Points to a Path2D.Double Object.
After that, i implemented the following method to make the enemys following this path:
public void forward(){
if(!pathIterator.isDone()){
pathIterator.currentSegment(current);
x = current[0];
y = current[1];
pathIterator.next();
}
else {
dead = true;
}
}
I think its clear what happens now: The Enemy is following, but the speed is that i moved the mouse with. So if i move to Mouse to fast, the enemy just.. "jumps" from one point to an other. To slow, its "sneaking" over that points. (And because im not an Robot, i cannot move the Mouse with the same speed ^^)
Talking of Robot: Yes, i could let a awt.Robot move my Mouse. But this isnt really possible too, because i have to draw complicated paths, which dont have any visible mathematics behind.
So, i want let this Enemys to move on this path with the same speed. My Problem: I don't know where to implement a "fix". I have 2 Ideas:
Maybe i could work on the Path creation: Instead of just adding the Points to the Path2D, maybe i could calculate points between the points where i moved to fast, or deleting points which are to near by each other. But: First, I don't know how to calculate this, (Is there any maths logic to achieve this?) And Second, when i do this i probably would'nt be able to change the speed of the enemys ingame, and that would be bad
The second idea i have, is to calculate the points between (oder the points to jump over), this should happen every frame, relative to the actual speed. But here im not experienced enough in maths to.
So, are that ways possible, and if yes, has someone an idea how to calculate this?
And, if not, what other possibilitys i have to achieve this?
Thank you, and sorry for the bad english!
All you need to do is define the speed of movement of the enemy inside the enemy class.
When it works out the next point to move to then create a direction vector by subtracting the current position from the new position.
Normalize the direction vector (so it is length 1) then multiply it by the speed and the tpf (time per frame).
Move by that amount instead of jumping to the next point.
(Note if the points are very close together or the framerate is low this can cause it to overshoot a bit, it should be fine though).

Bodies overlapping in 2D Physics simulation (Java)

I made a program in Java where circles can bounce into each other and gravitate towards each other.
For the most part (few circles on the screen), there are no noticeable bugs. The problem starts to happen when there is a large amount of circles on screen. Sometimes, the circles will overlap if it gets too crowded. It's as if the weight of all the other circles are crushing the circles together, causing them to overlap. Of course, there program doesn't know anything about how much a circle weighs, so it's not really crushing. Most likely, the piece of logic that handles resolving collisions is not able to handle crowded situations.
Circles are stored in an array, and each circle goes through the array using a for loop, comparing itself to the other circles. If the distance between the center of this circle and the center of the other circle is less than the sum of their radii, then the circles are colliding. The velocities of both circles are updated using an equation for collisions.
I think the problem occurs because if a circle is surrounded, it might receive an updated velocity into the circle behind it, while the circle behind it also receives an updated velocity into the former circle. In other words, the two circles get told to move toward each other, even though they are already touching. Once they overlap this way, I don't know why they don't undo their overlap.
I've tried restoring touching scenario if they are overlapping by finding the distance they are overlapped, then moving them apart from each other; each moves half the overlap distance apart. This doesn't change the circle's velocity, only their position.
This still doesn't solve the problem. If the circle is surrounded, and it overlaps with one of it's neighboring circles, its position is changed so they aren't overlapping, but this new position may cause it to overlap with another circle. Same problem.
If there was no gravity pushing the circles together, they would eventually spread out and resolve their overlapping issues, but the gravity prevents this from happening.
Further information:
Gravity is not taken into account when calculating new velocities after a collision.
Sounds like your hunches about what is causing the problem are correct in both cases.
Unfortunately, there's no easy way to fix this issue - it pretty much means rewriting your whole collision detection & resolution code from scratch. You have to work out the exact timing of the first collision, update everything only that far, resolve the collision (do your velocity update) then work out the exact timing of the next collision, then repeat...
Writing a good physics engine is hard, there's a good reason that there are many textbooks on the market about this subject!
The cheap 'fix' for your problem is to reduce the time interval for updates - e.g. instead of updating the physics in 33ms steps (~30fps), try updating in 16ms steps (~60fps). This won't prevent the problem, but it will make it much less likely to occur. Halving the time step will also double the time the processor has to spend doing physics updates!
If you use the cheap fix, the time step which will work best for you will be determined by how frequently collisions occur - more collisions means smaller time steps. How frequently collisions occur basically depends on how fast the circles tend to move and their population density (how much of a given area is filled by circles).
UPDATE: A little more info on the 'proper' approach.
The update would go something like this:
Start updating a frame. Let's say we want to update as far as time tF.
For every pair of circles, work out when you would expect a collision to occur (ignoring all the other circles). Let's call this time tC.
Find the smallest value of tC. Let's say this is for the collision between circles A and B, and let's call that collision cAB.
If tC <= tF, update all of the circles up to time tC. Otherwise, go to step 6.
Resolve collision cAB. Go back to step 2!
Update all the circles to time tF.
As you might imagine, this can get quite complicated. Step 2 can be quite tricky (and coputationally expensive) for non-circular objects (especially once you include things like angular momentum, etc.) although there are a lot of tricks you can do here to speed it up. It's also basically impossible to know how many times you'll be looping between steps 2 and 5.
Like I said, doing good physics simulation is hard. Doing it in real-time is even harder!

Categories

Resources