I'm having trouble getting circles to bounce off of each other. I've made 2 stand alone objects (c1 and c2, the unfilled white circles) that seem to work most of the time. My problem is when I try to make a vector to store them and to keep track of their collisions (b1 and b2 and the collision class) they act differently. You can click the lmb to grab one of the filled circles to make collisions easier.
If anyone has any ideas I would be eternally grateful, this has been driving me nuts for a while. I'm pretty sure it's the collision class that's cocking things up, or maybe where I'm checking for the collisions. I've written two collision Check() functions and both do seem to do the same thing. Basically I need a way of storing the body objects in a vector, iterating though, updating and checking for collisions, then adding these collisions to another vector and resolving them. Or put more simply, I need the filled balls to act like the unfilled balls, but more object orientated. Thanks
Looks like you've got the right idea; circular collision boils down to:
You've posted quite a lot of code; have you tried isolating the problem using some tests?
The only potential issue I can see at a glance is your usage of abs() - if this is cmath's function, you'll lose precision here - though this probably won't matter if you're not concerned about subpixel accuracy.
Edit I made a short video of the problem. The white circles are c1 and c2 and work for the most part. The pink circles are contained in a vector and use the penguin_collision class. They only interact with their respective colours.
https://www.youtube.com/watch?v=z0KNHp4H7VM&feature=youtu.be
Yeah I apologize for the amount of code, I thought I'd post all of it because I think the problem may be in how it's structured. The collision itself seems to be ok, it's getting the balls to bounce properly. The objects outside of the vector container do this, but in order to check every collision I would need to individually and manually check each object against every other object. I've tried to do this using a collision class which takes a vector of objects that records and "resolves" the collisions but the objects have unpredictable behaviour, most notably they seem to attract each other upon collision (and then all kinds of craziness happens). Since I'm using the same function for resolving the collision I can only assume the problem is with this collision class.
So this class takes a vector of body objects, Check()'s to see if any objects are colliding, if they are it Add()'s the two objects in to the vector body_a[] and body_b[], and (in theory) Resolve()'s the collisions by running through the vectors in pairs before finally Clear()'ing body_a[] and body_b[] ready for the next loop. Essentially I'm trying to do this -
But object orientated. I don't think individually checking each objects collision against every other object is "sustainable".
I can think of one problem. Every time you move an object you have to check it for collision with every other object again, otherwise you can end up with overlaps. Same goes for moving objects on the edge of the screen. You might have moved them onto another object.
When I did a circle collision demo, I used intercept times based on relative velocity. To scale it up, you need to build a collision table, of (N^2 + N)/2 size. Then you store the intercept times in the table, and react to them in order. To make things easier, don't move an object if it's way is obstructed. Having to move objects back out of another object sucks. Just don't let them overlap in the first place.
Some simple geometry and you can figure out whether a collision is even possible by using 2 line vs circle collisions. Or compute angular bounds of collision. Whatever.
I can maybe help you more with this if you're interested. I can't quite follow all the code you posted, but I didn't look that closely.
If you're interested in me actually checking out the code, post a compilable zip file with all the resources necessary and I will try it and maybe debug it a little bit if I get bored.
This is quite a tricky problem and if I remember correctly, in the general case, you need to split each time step - calculate the 'sub-step time' to the first collision, separate the colliding bodies, re-compute velocities and repeat. Do some googling for 'Erin Catto' he did some good lectures on this.
For your case you are double-counting your collisions, body A on B and B on A.
I changed your code (line 185 in your first listing) to
void CPenguin_Collision::Check(std::vector<CPenguin_Body*>body){ for(unsigned int i=0;i<body.size();i++){ for(unsigned int j=0; j<i; j++){ if(body[i]->id != body[j]->id){ if(body[i]->CheckCollision(body[j])){ Add(body[i],body[j]); } } } } }
and (lines 311-315)
for(unsigned int i=0;i<my_body.size();i++){ my_body[i]->Update(); my_body[i]->Bound(); } penguin_collision->Check(my_body);
and it looked 'better' to me on a first glance.
I made a small guide to using intercept times or overlap checks for circle vs circle collisions on the wiki here :
https://github.com/liballeg/allegro_wiki/wiki/Circle-V-Circle-collision
I'll add more to it later, like a collision table, but it fully explains circle vs circle intercept calculation of collision time.
I changed the abs to fabs dbthompson. It may just be me but the circles don't seem to stick to each other as much. It happens maybe every 20 collisions now.
I can see that problem with overlaps Edgar, tbh I can barely understand the code I have at the moment but I will check out those guides. Is it that much more coding in general or more about understanding the concepts? I'm not sure whether the circles are getting stuck because of overlap but it seems to happen at random. I was hoping it was where my collision or overlap detection was a bit off or missing some calculation. Would the overlap happen with just two objects?
That's was exactly the problem Peter, I realised this morning I was doubling up one of the position updates although I still had no idea how to fix it. Your edit seems to have done the trick.
Also one last question, are there any small changes I can make to improve the code any more or anything I can do to improve my coding in general? I'm probably breaking a million and one conventions and rules but I'd like to get better.
Thank you again for all your help guys
Also one last question, are there any small changes I can make to improve the code any more
Two things I noticed:
I would recommend avoiding passing a vector (or any container) by value (line 67) because that makes a copy every time. This is inefficient and also loses any changes you might make to the container in the body of the function. A reference or constant reference is better, unless a copy is what you really want.
The result of sqrt is always positive so you don't need abs in line 123
This is quite a tricky problem and if I remember correctly, in the general case, you need to split each time step - calculate the 'sub-step time' to the first collision, separate the colliding bodies, re-compute velocities and repeat. Do some googling for 'Erin Catto' he did some good lectures on this.
Basically, you're doing a binary search over time to find the first collision time.
Something you can do to make objects stop 'sticking' to each other is to allow overlap. If c1.Future(0.0).Overlaps(c2.Future(0.0)), no collision.
I can see that problem with overlaps Edgar, tbh I can barely understand the code I have at the moment but I will check out those guides. Is it that much more coding in general or more about understanding the concepts? I'm not sure whether the circles are getting stuck because of overlap but it seems to happen at random. I was hoping it was where my collision or overlap detection was a bit off or missing some calculation. Would the overlap happen with just two objects?
Given that you have 'boundaries' that move objects, overlap can happen anytime two objects follow each other toward the edge. The collision with the edge is still a collision.
Basically, overlap can happen any time you move an object. The solution then is to never move your object by a delta time greater than the first possible collision solution. A collision should never change the position of an object, only it's velocity or momentum or impulse. Because a collision is instantaneous transferral of energy. The objects don't have time to move, and they wouldn't move until the energy transfer is complete.
This is why intercept tables save you all this trouble.
Read the guides I put up, they're very simple, and self explanatory, with heavy description.
https://github.com/liballeg/allegro_wiki/wiki/Circle-V-Circle-collision
I'm currently working on a demo program and a collision table that will save you many many headaches.
As for code advice, I would recommend you work on your vector class and your circle class. The vector class could really use operator overloading, look into it, and the circle class needs methods for things like future position, and Update(double dt).
UPDATE
I finished a small demo you can try. src and win32 binary are included.
{"name":"611751","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/c\/fcf0cd94f1968d5d6580b01040a57fc9.png","w":1026,"h":801,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/c\/fcf0cd94f1968d5d6580b01040a57fc9"}
Tested, works fine.
I'm not used to friction-less physics, but it does seem to be more or less of a natural movement.
One surprising behavior is in small-large collision : a slow-moving large ball hitting a slow-moving small ball will hurl the latter at a surprising velocity. The energy sum is probably unchanged, but I feel the amount transferred is more than expected.
I forgot to say the controls are LMB to launch a small ball, RMB to launch a large ball, and R to toggle screen clearing (that way you can see the trails).
Balls that overlap are shown in red.
One surprising behavior is in small-large collision : a slow-moving large ball hitting a slow-moving small ball will hurl the latter at a surprising velocity. The energy sum is probably unchanged, but I feel the amount transferred is more than expected.
Yeah, I don't know actual physics. All I did was transfer the normal momentum to the other ball. A larger ball has more mass, so more energy is injected into the smaller ball, which results in higher velocities.
What would be more natural? Did you have some equations in mind?