How to test if one rect is in another rect?
Alright, so I'm working on a game and I have found out that my enemies don't like my collision detection that works perfectly for my player. After a little debugging I found out it's because my enemies are bigger than my tiles, while my player is smaller than my tiles.
Now I need to be able 开发者_JS百科to make big enemies and bosses, so this just won't do. so I need to figure out a better way to test collision detection. This is how I am currently doing it:
up and down:
if((enemy.left > tile.left && enemy.left < tile.right || enemy.right > tile.left && enemy.right < tile.right) && enemy.top < tile.bottom && enemy.bottom > tile.top){
//collision
}
left and right:
if((enemy.top > tile.top && enemy.top < tile.bottom || enemy.bottom > tile.top && enemy.bottom < tile.bottom) && enemy.left < tile.right && enemy.right > tile.left){
//colision
}
In Java, use intersects(Rectangle r)
.
Here's how to correctly do the separating axis tests (for oriented bounding boxes, like you're doing).
if (firstObject.Left < secondObject.Right && firstObject.Right > secondObject.Left
&& firstObject.Top < secondObject.Bottom && firstObject.Bottom > secondObject.Top)
{
// Intersecting
}
Go to this site, and play with Figure 3, making all of these true one at a time. Then break each of the tests, one at a time. You'll see empirically that it works, and is about as simple as you can get:
http://www.metanetsoftware.com/technique/tutorialA.html#section1
If you feel like it, read through the whole set of tutorials. It'll be worth it once you start packing more features into your game :)
In .NET languages, you can use the Rectangle.IntersectsWith(Rectangle other)
method to perform very basic collision detection.
For anyone working in Objective-C looking for the same answer you can use:
bool CGRectIntersectsRect(CGRect rect1, CGRect rect2)
I think the problem lies in
enemy.top < tile.bottom && enemy.bottom > tile.top
(In first code), this will only be true if enemy is within the tile fully (height-wise)
enemy.top > tile.top && enemy.top < tile.bottom || enemy.bottom > tile.top && enemy.bottom < tile.bottom
Like you have done with the left + right check.
Just to clarify this would mean the first check you gave would be:
if((enemy.left > tile.left && enemy.left < tile.right || enemy.right > tile.left && enemy.right < tile.right) && (enemy.top > tile.top && enemy.top < tile.bottom || enemy.bottom > tile.top && enemy.bottom < tile.bottom)){
//collision
}
And with this I dont think you would need seperate up/down left/right checks, this should return true if ANY part of enemy is within tile
The sprite is wider than the tile, but the "left-right" code doesn't check for that case.
If i graph your code, it simply checks whether the enemy left or the enemy right lies within the tile:
(enemy.left > tile.left && enemy.left < tile.right
|| enemy.right > tile.left && enemy.right < tile.right)
// graphed as<br>
// TL EL TR ----- or ----- TL ER TR<br>
but if the entire tile lies within the enemy region, no hit is detected:
// EL TL ----- and ----- TR ER
Similarly, the Tile is smaller vertially than the enemy, so it is necessary to check the if the entire tile lies within the enemy. The complete graph/pseudo code is:
is_hit :
// T{L,R,T,B} => tile, E{L,R,T,B} => enemy
// left-right:
[
TL EL TR ----- or ----- TL ER TR
. or .
EL TL ----- and ----- TR ER
]
.and.
// top-bottom:
[
TT ET TB ----- or ----- TT EB TB
. or .
ET TT ----- and ----- TB EB
]
In .Net
there is already a method named Intersect(Rect rect)
in Rect
class.
精彩评论