I'm working on an infinite runner and I need to have collision detection between a single sprite, and any sprite out of a CCArray of sprites. How do you suggest that I do this? Currently this is the method that I call to check for collisions, but it isn't working.
bool RunningScene::spritesAreColliding(cocos2d::CCSprite *spr1, cocos2d::CCSprite *spr2)
{
//Take the bounding box of the two sprites that are bounded
CCRect r1 = spr1->boundingBox();
CCRect r2 = spr2->boundingBox();
if (r1.intersectsRect(r2)) { //Check if the bounding boxes are intersecting and return a true/false
return true;
} else {
return false;
}
}
I use it in an if statement, and if it returns true, the if statement works.
I'm not hoping for pixel perfect collision detection, but I'm wondering if that method will work for checking collisions, and I'm wondering how to access any sprite from the CCArray that happens to be colliding with the _runner sprite.
I'm not sure why your code isn't working, because I can't see what you are doing. Suppose that the method returns true. What do you do?
Collision detection is difficult. I suggest you check out the appropriate chapters of this book: Real Time Collision Detection.
There are two approaches: continuous and discrete.
It looks like you're trying to use discrete collision detection. This is when you react to collisions after they happen. You need to find the penetration axis, so that you know in which direction to 'push the boxes apart'. One simple yet slow way to accomplish this is to do a sort of 'binary search' for the moment just before they began colliding. Take the objects to their positions before their velocities were applied (start of frame). Now apply half of their velocities. Are they intersecting? If not, apply 0.75 of their velocities, and if yes, apply 0.25 of their velocities. Repeat for a preset number of iterations and until they are no longer intersecting.
You will also have to set their velocities so that they either 'bounce back' or at least stop moving along the axis that they last intersected on.
Discrete collision detection is problematic. The most well known problem is tunneling. This is when objects are moving so fast that they do not intersect. When their velocities are applied, the 'move through one another' and the collision is never caught. For 2D collision detection, I recommend the continuous approach.
Related
I have a rotated Rectangle inside a closed tile map of rectangles.
What would be the best way to check if the player (which is the rotated rectangle) is intersecting with one of the rectangles of the tile map?
Picture from inside the game to better show what the map looks like:
If it matters, the Player's type is sf::Shape and the map's data is inside an int array.
SFML does not provide collision detection, it only has method to check if two axis-aligned rectangles intersect. If you need something more complex, you will have to implement if yourself.
If you don't need precision detection, you can test Sprite.getGlobalBounds().intersects(...) with the rectangle of the map.
If you want ideal collision detection, you have more then one option:
Pixel perfect Collision. First check if bounding box intersect the map tile and them check all non-transparent pixels for collision. Not very fast but easy to implement and may be suitable for your case.
Mathematical methods, there are more that one, but take a look at Separating Axis Theorem. If your are only limited to rectangles (or/and circles and convex polygons), it will work best.
For anyone still having this issue:
You should look into the getTransform() and getInverseTransform() functions of sf::Transformable (https://www.sfmldev.org/documentation/2.5.1/classsf_1_1Transformable.php). Getting the inverse transforms of the player and a specific wall allows you to use a simple AABB collision algorithm (like SFML already implemented it in getGlobalBounds().intersects(...)). You basicly look at the local coordinate system of the player and how the wall is positioned to it, all translations, rotations and scaling ignored.
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).
So, I have a Triangle->AABB collision algorithm and I have it returning the triangle that the AABB collided with. I was hoping with the 3 vectors of the triangle and the direction/magnitude of the movement would let me determine a deflected vector so that when you run against the wall at an angle you move slower, depending on the angle of collision, but along side the wall. This would remove the sticky collision problem with only moving when there is not a collision. Any suggestions or references would be greatly appreciated! Thanks.
First, I would convert magnitude/direction to a vector (it's much more convenient).
Then (c++):
float towards=dot(velocity,norm); // velocity component into triangle
if(towards<0) // is moving into triangle
velocity-=towards*norm; // remove component
Then it can't move into the triangle. towards<0 might need to be reversed depending on your normal. It's also nice to have a spring force pushing it out.
Remove the component of the velocity along the normal of the triangle.
The idea is that you can represent the movement as the part that's moving "into" the triangle and the remainder (which will be in perpendicular directions). If you then just move with the remainder, you will no longer be getting any closer to the triangle by the movement (or further, but you shouldn't be detecting a collision in that case).
In pseudo-code:
// v := velocity vector of moving object
// p[3] := points that make up the triangle
triangle_normal = cross(p[2]-p[0], p[1]-p[0])
problematic_v = project(v, onto=triangle_normal)
safe_movement = v - problematic_movement
Note that this intentionally doesn't preserve the magnitude of the movement vector, as doing so would make you slide along a wall very quickly when running straight at it.
For more details and some nice pictures, see Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres at Gamasutra. You're not using spheres, but you are essentially doing a perfectly plastic (since you don't bounce) collision.
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'.
I'm working on a little 2D platformer/fighting game with C++ and SDL, and I'm having quite a bit of trouble with the collision detection.
The levels are made up of an array of tiles, and I use a for loop to go through each one (I know it may not be the best way to do it, and I may need help with that too). For each side of the character, I move it one pixel in that direction and check for a collision (I also check to see if the character is moving in that direction). If there is a collision, I set the velocity to 0 and move the player to the edge of the tile.
My problem is that if I check for horizontal collisions first, and the player moves vertically at more than one pixel per frame, it handles the horizontal collision and moves the character to the side of the tile even if the tile is below (or above) the character. If I handle vertical collision first, it does the same, except it does it for the horizontal axis.
How can I handle collisions on both axes without having those problems? Is there any better way to handle collision than how I'm doing it?
XNA's 2D platformer example uses tile-based collision as well. The way they handle it there is pretty simple and may useful for you. Here's a stripped down explanation of what's in there (removing the specific-to-their-demo stuff):
After applying movement, it checks for collisions.
It determines the tiles the player overlaps based on the player's bounding box.
It iterates through all of those tiles...
If the tile being checked isn't passable:
It determines how far on the X and Y axes the player is overlapping the non-passable tile
Collision is resolved only on the shallow axis:
If Y is the shallow axis (abs(overlap.y) < abs(overlap.x)), position.y += overlap.y; likewise if X is the shallow axis.
The bounding box is updated based on the position change
Move on to the next tile...
It's in player.cs in the HandleCollisions() function if you grab the code and want to see what they specifically do there.
Yes. Vector based collision will be much better than tile based. Define each edge of a tile as lines (there are short cuts, but ignore them for now.) Now to see if a collision has occured, find the closest horizontal and vertical line. if you take the sign of lastPos.x * LineVector.y - lastPos.y * LineVector.x and compare that with thisTurnsPos.x * LineVector.y - ThisTurnsPos.y * LinePos.x. If the signs of those two values differ, you have crossed that line this tic. This doesn't check if you've crossed the end of a line segment though. You can form a dot product between the same lineVector and your curPosition (a little error here, but good enough probably) and it is either negative or greater than the line's magnitude squared, you aren't within that line segment and no collision has occured.
Now this is farily complex and you could probably get away with a simple grid check to see if you've crossed into another square's area. But! The advantage of doing it with vectors is it solves the moving faster than the size of the collision box problem and (more importantly), you can use non axis aligned lines for your collisions. This system works for any 2D vectors (and with a little massaging, 3D as well.) It also allows you slide your character along the edge of the collision box rather easily as well because you've already done 99% of the math needed to find where you are supposed to be after a collision.
I've glossed over a couple of implementation details, but I can tell that I've used the above method in countless commercial video games and it has worked like a charm. Good Luck!