Javascript - Circle-Circle Collision Issue
Asked Answered
B

3

2

I am making a game in HTML5, Canvas, and this is my code for resolving collision between two moving circles:

function resCCCol(a, b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;

    var dist = dx * dx + dy * dy;

    var vx = b.vx - a.vx;
    var vy = b.vy - a.vy;

    var dot = dx * vx + dy * vy;

    if (dot > 0) {
        var scale = dot / dist;

        var cx = dx * scale;
        var cy = dy * scale;

        var mass = a.r + b.r;

        var cw1 = 2 * b.r / mass;
        var cw2 = 2 * a.r / mass;

        a.vx += cw1 * cx
        a.vy += cw1 * cy
        b.vx -= cw2 * cx
        b.vy -= cw2 * cy
    }
}

If I set the coordinates so that the circles overlap but still have their velocity both at 0, the circles won't push out each other, that is the problem. How do I fix this?

EDIT: Fiddle: http://jsfiddle.net/yP7xf/2/, click "Glitch it!" to see the glitch, as you see they won't separate.

Burghley answered 7/4, 2014 at 17:49 Comment(7)
Make a fiddle please.Explode
jsfiddle.net/yP7xf/2 - ThereBurghley
It would help if you added a few comments to illustrate your code. But in general, if the two circles are overlapping but have a velocity of zero, just what would you expect them to do? They have to be moving before they can bounce or it won't be possible to calculate a new velocity. It's probably better to make sure they don't get in that state in the first place.Rivalee
Off-topic but there is a trick to check distances against a threshold and avoid a square root. You know that if sqrt(x) < y then x < y*y. In your case, you can check if dx*dx+dy*dy <= (a.r+b.r)*(a.r+b.r). Also you can precompute (a.r+b.r)*(a.r+b.r) and only update it if/when one of the radiuses changes, then distance tests are very fast (2 multiplies, 1 add, and a compare -- dx*dx+dy*dy <= a_plus_b_squared).Jannette
As for your question; can you describe in more detail the exact behavior you're trying to obtain?Jannette
Off-topic More like a daily thingBurghley
I want them out of eachother by setting eachs coordinates so that they are perfectly aoigbed out of eachotherBurghley
I
2

I'm not sure what the purpose of dot is (maybe I'm missing some maths knowledge here), but two circles colliding happens if dist < sum(radii). Should this occur, you should deflect the circles, but ensure they have at least some small speed to ensure they separate.

Irradiance answered 7/4, 2014 at 18:23 Comment(11)
And how do you ensure that?Burghley
Well, you have horizontal and vertical speed, maybe check if they're both zero, and if so adjust them so that the circles are moving away from each other?Irradiance
Isn't there anyway to put them just outside of eachother?Burghley
You could determine the direction to move them apart, and sum(radii)-dist is the distance to move them (combined, so maybe /2 each?)Irradiance
Mass must also be included then, but isn't there anyway to just move them directly from each other than adding velocity?Burghley
This conversation is leaning towards a question more appropriate for the Physics Stack Exchange.Whet
So you don't wanna discuss this anymore or..?Burghley
I'm saying that I'm no physics master, and if you want to talk about physics, there are plenty of gurus on the Physics Exchange that would know better ways to calculate the angle at which the circles deflect, their inertias, velocities, etc.Whet
Although I'm not sure how much physics can help when the two objects start intersecting each other with zero velocity...Irradiance
No, right now I just want them repositioned, not using velocitiesBurghley
Just put them aligned out of eachother by their distance angleBurghley
W
2

When two circles overlap with no velocity your resCCCol() method won't work since dot is 0. Even if you change the if statement to execute on dot >= 0, you're still left with 0 velocity.

if (dot > 0) { //dot === 0
    var scale = dot / dist; //scale === 0

    var cx = dx * scale; //cx === 0
    var cy = dy * scale; //cy === 0

    var mass = a.r + b.r;

    var cw1 = 2 * b.r / mass;
    var cw2 = 2 * a.r / mass;

    a.vx += cw1 * cx // 0
    a.vy += cw1 * cy // 0
    b.vx -= cw2 * cx // 0
    b.vy -= cw2 * cy // 0
}

You should handle cases when dot === 0. The easiest way is to simply give them a set velocity when the velocity is 0:

if (dot > 0) { 
    ... 
} else {
    a.vx = 1;
    a.vy = 1;
    b.vx = -1;
    b.vy = -1;
}

This, of course, will only propel them away from each other towards opposite corners of the screen, but you could easily implement something that better adheres to the laws of physics (ignoring the fact that two objects can't take up the same space).

Whet answered 7/4, 2014 at 18:35 Comment(6)
I mean like rapidly just move their position, instead of adding velocity.Burghley
The velocities for both circles would still be 0, so that would not work.Whet
No i mean just put them outside of eachother by their coordinates and distance angle, if they are in to eachotherBurghley
That would certainly work if you don't want them to deflect. Your question isn't entirely clear, if that's the conclusion you were getting at. We're simply here to help make code work, but physics isn't necessarily our strong suit.Whet
What do you mean our?Burghley
The entire Stack Overflow community on average; at the very least I speak for myself.Whet
R
0

It's not entirely clear what the best way to handle this would be, and I think it would be better to make sure you don't end up in this situation in the first place (by making sure they don't ever overlap with zero velocity), but a quick and dirty fix is to check dot === 0 and if so, give them some velocity. For example:

if (dot === 0) {
    // numbers pulled completely out of thin air...
    a.vx = 0.5;
    a.vy = 0.5;
    b.vx = -0.5;
    b.vy = -0.5;
}

http://jsfiddle.net/yP7xf/5/

Now what velocity should you give them? That's something you'll need to work out. Probably you want them to move apart so you can probably calculate some vector based on a line from the center of one to the center of the other and send one in one direction along that vector and the other in the other at whatever speed you think is appropriate. But if they are laid exactly on top of each other (centers at the same point), then you'll need to account for that case too.

Rivalee answered 7/4, 2014 at 18:36 Comment(6)
imgur.com/yEFbUdL, isn't there anyway to put them exactly away from eachother instead of adding velocity, just set the position to be outside the other?Burghley
@Murplyx Math.atan2(b.y - a.y, b.x - a.x); will give you the angle in radians (so you can use Math.cos and Math.sin).Antietam
@Murplyx: Sure, just calculate the line from the center of one to the center of the other and move them along that line until they aren't overlapping anymore. But that's a trigonometry question and I'm too rusty to do that off the top of my head.Rivalee
@Murplyx: As I said, too rusty. This one's on you.Rivalee
Well is there anyway not using trigonometry, it's expensive?Burghley
@Murplyx: I'll go back to my original comment about not letting them overlap in the first place. How are you getting into this situation to start with? How are they placed at first? Can you simply avoid it there?Rivalee

© 2022 - 2024 — McMap. All rights reserved.