I am trying to write a very stripped down, simple collider similar to Box2D-- absent all physics, rotation, etc. I'm doing this both to keep the code footprint tiny and understandable, and also to simply learn the inner workings of these things personally.
All I'm trying to do is collide circles and lines, and keep them from getting embedded in eachother.
Box2D does this almost perfectly-- very tiny amounts of overlap! However, when I write my own simple simulator, I get a lot of overlap: .
When I run the same simulation using Box2D (this is just all circles chasing a point in the center of the screen), I get no visible overlap at ALL.
In pseudocode, this is what I do:
For each Circle In List:
Determine who will collide with the circle in next step
Sort collisions by closest first
For each possible collision:
Add the unembed vector to the Circle's movement vector
...and then:
For each Circle In List:
At the movement to the circle
So, if the circles don't get pushed into anything else, this also works perfectly. When things pile up, though, it does NOT work, and I know why-- the unembeds simply accumulate and everyone pushes and jostles because later circles get unembedded into earlier circles, and at the end of the simulation, some are just stuck inside others. Makes enormous sense.
Here's where I'm confused:
Near as I can tell, Box2D operates EXACTLY the same way-- get possible collisions, unembed from eachother, done. But Box2D never, ever, gets overlapping like mine (or it gets them so small as to not matter).
Can someone tell me what step I have missed here? I can do tweaking to improve things (like iterating anyone who collided again and again... but Box2D does not appear to do this, and I want to understand while keeping the code light and fast).
Thanks!
Pertinent real code below:
aO->mPos = x,y of object
aO->mMove = x,y of movement this step
aO->mRadius = radius of object
aO->MovingBound() = bound of object including the move
void Step()
{
EnumList(MCObject,aO,mMovingObjectList)
{
mTree.GetAllNearbyObjects(aO->MovingBound().Expand(aO->mRadius/4),&aHitList);
aHitList-=aO; // Remove self from list
if (aHitList.GetCount()>0)
{
// Sort the collisions by closest first
if (mSortCollisions)
{
// Snip, took this out for clarity...
// It just sorts aHitList by who is closest
// to the current object
}
// Apply the unembedding
EnumList(MCObject,aO2,aHitList) CollideObjectObject(aO,aO2);
}
}
// Do the actual moves
EnumList(MCObject,aO,mMovingObjectList)
{
mTree.Move(aO->mProxy,aO->Bound(),aO->mMove);
aO->mPos+=aO->mMove;
aO->mMove=0;
}
}
void CollideObjectObject(MCObject* theO1, MCObject* theO2)
{
float aOverlap=gMath.DistanceSquared(theO1->mPos+theO1->mMove,theO2->mPos+theO2->mMove);
float aMixRadius=theO1->mRadius+theO2->mRadius;
if (aOverlap<=aMixRadius*aMixRadius)
{
Point aUnembed=(theO1->mPos-theO2->mPos);
float aUnembedLength=aMixRadius-sqrt(aOverlap);
aUnembed.SetLength(aUnembedLength);
float aMod=.5f;
if (theO2->mCollideFlags&COLLIDEFLAG_STATIONARY) aMod=1.0f;
theO1->mMove+=aUnembed*aMod;
}
}
Resolving collisions between many objects is quite a difficult problem because, in addition to the basic maths of collisions, you have to work much more diligently at fixing the accumulation of mathematical errors that come from approximative solvers (physics in the real world work based on integration which dictates infinitesimally small time-steps; while in our simulations, we usually only solve some 60 times a second).
Let's have a look at Box2D's constraint solver loop, located in b2island.cpp: In every world step, the collision resolver does not only run once. It will repeat velocityIterations times, which in the official test cases is usually set to 6 or 8. And that is what you will have to do as well.
Related
I have a small application I have built where there are a few balls on a blank background. They all start flying through the air and use the physics I wrote to bounce accurately and have realistic collision responses. I am satisfied with how it looks except I have an issue where when my balls land directly on top of each other, the attach together and float directly up.
Here are the functions involved
https://gist.github.com/anonymous/899d6fb255a85d8f2102
Basically if the Collision function returns true, I use the ResolveCollision to change their velocities accordingly.
I believe the issue is from the slight re-positioning I do in ResolveCollision(). If they collide I bring them a frame or so backwards in location so that they are not intersecting still the next frame. However, when they are directly on top they bounce off eachother at such small bounces that eventually stepping back a frame isn't enough to unhook them.
I'm unsure if this is the problem and if it is, then what to do about it.
Any help would be awesome!
The trick is to ignore the collision if the circles are moving away from each other. This works so long as your timestep is small enough relative to their velocities (i.e. the circles can't pass through each other in a single frame).
When the circles first collide, you will adjust their velocity vectors so their relative velocity vector pushes them apart (because a collision will do that). After that, any further collisions are spurious because the circles will be moving apart, and will eventually separate completely. So, just ignore collisions between objects that are moving apart, and you should be fine.
(I've implemented such an algorithm in a 3D screensaver I wrote, but the algorithm is entirely dimension-agnostic and so would work fine for 2D circles).
I have made several attempts to fix this and read all I could find here/forum/google. I used a CCD treshold mush lower than my objects move speed and using a CCD radius much smaller than the objects half radius. The only thing this does is make the multisphere get stuck on seams. I also tried to set ERP/ERP2 to 0.9/1.0.
[EDIT] Ok, so after some more reading; CCD will not work if the sphere is already touching the ground and ERP only affeccts objectts with joints if I understand correctly.
The ground is a trimesh made in Blender and using the obtainStaticNodeShape to get the shape. I have tried to scale the mesh to get smaller polygons but even the smallest (for the game acceptable) size does not work, about 32k indices with 11k polys, 500x500 units, the multisphere has a radius of 0.45 units.
[EDIT] the multi-sphere is two spheres on top of each other and they are restricted to angular movement around the Y-axis only, so no rolling.
The sphere gets "sucked" fast through the ground it does not sink slowly. I tried to make the fixedtimestep smaller 1/420 with 64 substeps did not give any better results. This happens most often while ascending or descending a slope. My ground is gently sloped but an incline of 20% seems to be enough for it to fall through a lot but it can happen on level ground too, just not as often.
When I did my first test I used a big stretched out cube as ground and it worked well.
So my problem now is I don't even know why this is happening so I have no idea what to try next? Can anyone please give me a solution or some pointers.
Is there any use in increasing the multi-sphere size (for the game I can not increase more than 25-30%) I have not explicitly set any collision margins but I think this would just make my sphere float over the ground? Is there any profit in changing the ground from a static object to a kinematic?
Would it work to use a raytest from the sphere straight down and push it up if it is lower than the ground? I think not, why would it fall through if it could detect the ground in the first place..?
[EDIT: additional info]
There are quite a few occurrences of similar problems floating around on forums and also here at stack overflow. Most seem to be about very small objects. Small objects (>0.2m) is clearly not a good option for bullet unless you want to increase the number of simulation steps quite a lot. My problems does not seem to fall under this category since my smallest object is 0.9m in diameter?
I have now also done a debug draw to see the normals of the trimesh that I use as ground. I can not find any errors with the normals.
I also tried to increase the collission margins of the speheres but to no avail.
I further tried to use suggested settings:
((btDefaultCollisionConfiguration)world.collisionConfiguration).setPlaneConvexMultipointIterations(3,3); ((btDefaultCollisionConfiguration)world.collisionConfiguration).setConvexConvexMultipointIterations(3, 3);
No difference.
I did however read about big trimeshes not working very well for raycasting, my mesh is big 512x512 units but I am not sure if this could cause my object to fall through the mesh?
I also read that sphere shapes has problems with trimeshes, but again I am not sure if this would be my case? The sphere I am using is locked for rotation on all axes.
I have also tried using a btCapsule but it gave same results.. Would a cylinder work better?
[EDIT]
I have tried using a cylinder instead since sphere and capsule did not work. The cylinder is working a lot better. I have still got it to fall through once though. The clyinder was jerking around a lot before it went through where the sphere/capsule would just go through really fast and easy. Maybe this could be a clue of whats the underlaying problem? A cylinder is not the best for a character shape though..
An other possible reason could be if a triangle in the mesh has too long sides or a large ratio between sides. I found a few of those on a slope where my sphere always falls through. If this is indeed the problem can I do anything about it except manually editing the mesh in Blender?
As you can see there are a lot of these questions and a lot of possible answers and I have no idea which one corresponds to my case, someone with better insight giving some pointers would mean a lot, thanks!
I'm working on a Minecraft like game for educational purposes. The rendering is great so far even with 1024x1204 blocks but now that I started integrating the player collision I'm having problems.
I have a aabb for the player and aabb's for all the blocks around him. These are created dynamically and it works out pretty fast.
My problem goes as following:
I have speed vector and the current position. For each axis I calculate the potential position and make out an aabb. I check for collisions and it's free I move there otherwise I set the speed for that component to 0. I separate the axis since I want my player to slide in a direction of partially facing a wall.
The order for the axis is y,x,z. The collision response is great but I'm having some problems with the corners as it sometimes get's stuck in the world without being able to move. Not sure what the reason is for this.
I do not want to implement actual physics since those are more demanding and basically just too much for what I need.
Do you guys have any suggestions on how to implement this in a nice way? I did some searching but I didn't find anything useful for this particular situation.
This is a bit abstract in a sense that the cause of your problem can be related to many things. From the top of my head, maybe a bug in your collision detection code: somehow it allows the objects to cross boundaries by 1 (or more) unit. So when the next collision is computed 1 or more dimension is stuck (imagine having an arm already inside the wall when collision is detected. You can't get your arm out because it collide with the interior of the wall boundary)
I have a simple question about a game I am making using box2D and cocos2D. I started using the physics engine yesterday so I am rather inexperienced with its usage and capabilities. My game involves rolling a ball around the screen using the accelerometer. I want to add holes to the ground that if the ball rolls into, it will then require a greater acceleration via the accelerometer to escape the hole pocket. I've toyed with friction, linear damping, modifying the accelerometer's gravity vector, and tried adding attractive forces but I haven't had too much success and some of it doesn't really simulate well what I want happening. Basically I just want to create some sensors and give them the properties of a small pocket a ball can fall in to. Any tips and advice is much appreciated. Thanks
I suggest you to use Level Helper . Its an awesome tool to create physic based games.
You can find it here
You could take the y position of the ball every frame and if it is below a certain threshold, then it is in a hole. Based off on this, if the ball is in a hole, reduce the sensitivity. When the ball exits the hole, put the sensitivity back to normal.
As for creating the holes, use Vertex Helper to create bodies that will correspond to your sprites.
If you need more explanation, feel free to ask.
Elaborated:
Now, basically in the picture, I am depicting what I tried to describe earlier. All you really have to do is to change the tilt sensitivity if the player's Y position is below a certain point. I just used 50 as an example.
Some pseudocode:
- (void)update:(ccTime)dt
{
if (player.position.y >= 50) { //If the player's y position is above or equal to 50
if (sensitivity != normalSensitivity) { //We don't need to set it every frame, so lets check
sensitivity = normalSensitivity;
}
}
if (player.position.y < 50) { //If player's position is below our threshold of 50
if (sensitivity != limitedSensitivity) { //Check so we don't set the sensitivity every frame
sensitivity = limitedSensitivity;
}
}
}
Now, as far as Vertex Helper is concerned, it is an open source tool (I believe) that helps you define vertices for custom shapes that can then be copied and pasted directly into your box2d or chipmunk cocos2d project. It can be fond here.
I suggest googling around for tutorials on how this is used. It is very simple, but you may need a quick reference to get you started.
Finally, something to remember, is that box2d can only work with convex shapes, not concave.
A convex shape is a shape where in is impossible to draw a line from any vertex to another without passing through the shape itself. Basically something that has no indentations in it.
I hope this helped. I'm not sure I can elaborate anymore than I have, but if you have more specific questions, feel free to ask.
I'm having hard time learning collision detection by experience. I'm making a box game, à la Minecraft, and am at the stage of implementing collision detection.
I've done x and y axis', since everything consists of cubes I would like to make my own collision detector and make it as light as possible.
Is there a way to make "pixel perfect" collisions, that is when the player's bounding box (or circle) touches a box it registers as a collision? Right now this is what I did:
if(-TOUCH_DISTANCE-1 < yPlayer-yBox && yPlayer-yBox < TOUCH_DISTANCE-1)
{
collisionNorth = true;
}
if(-TOUCH_DISTANCE+1 < yPlayer-yBox && yPlayer-yBox < TOUCH_DISTANCE+1)
{
collisionSouth = true;
}
It basically detects the collision within a certain margin and that means errors, which I don't like :(. Notice the +/-1 which offsets the "collision wall" to the respective side of the box.
This works, on lower speeds, but once there's some action (when I crack up the speed variable) the collision can't be detected anymore since I go too fast and pass right through the cube... Is there a way to make it wallhax0r proof?
This is especially annoying on z axis, when the player falls at high speed and even when defining a respectable collision margin it will ultimately look nasty (player half buried).
You've identified one of the problems of using discrete mathematics to model the path of an object. At time t the object is "here" and at time t + delta it's "there" - without actually having passed through the points in between.
You can get more accuracy by decreasing delta, but ultimately you are going to hit the limit of what you can calculate in that time interval.
If you can detect a collision approaching by using a relatively large time delta and loose bounding box you could then crank up the accuracy, but again you are going to hit limits.
Converting to a continuous model might help - but may take more computational power. You could switch to this when your objects are close so you're not doing it all the time.
Sorry I've not got a definite answer, only pointers.
Usually what you need to do is keep track of the previous position of the objects as well as the current position. Then when you update, you can check if the objects intersected during the time period, rather than if they intersect 'at the moment'.