Tasnu Arakun
2004.09.22, 09:25 AM
hi,
i'd like to discuss which collision detection i should adopt for a 2d arcade-style game i'm writing at the moment. collisions come in two distinct types: those whose effect is always the same (objects getting destroyed) and those whose effect vary depending on the objects location, speed and direction. the latter in this case is deciding upon a new direction vector for a bouncing ball (one affected by gravity).
the game area consists of 16 * 16 tiles - some are empty, others hold "bricks" of different kinds. now "balls" are to fall from above, collide and eventually come to a rest upon these bricks. the balls all have different behaviours which, among other things, affect their movement. thus i need to check what side of the brick the ball has hit (and the direction of the ball).
both balls and bricks have a rectangle bounding box (although that can easily change). what my first collision code did was essentially to check the location of the ball compared to the brick. e.g. if the ball struck the brick from above and the direction is negative (downwards), i have a collision and have simply to multiply the y-value by -0.9 (or whatever). each ball is allowed to collide only once during each engine tick. also a collision turns of some of the special behaviour (like always moving in the direction of the player) during that engine tick.
int collides( NSRect rect1, NSRect rect2 ) {
if ( !NSIntersectsRect( rect1, rect2 ) ) return NONE;
if ( NSMinY( rect1 ) < NSMinY( rect2 ) && NSMaxY( rect1 ) < NSMaxY( rect2 ) ) return NORTH;
if ( NSMinX( rect1 ) < NSMinX( rect2 ) && NSMaxX( rect1 ) < NSMaxX( rect2 ) ) return WEST;
if ( NSMinY( rect1 ) > NSMinY( rect2 ) && NSMaxY( rect1 ) > NSMaxY( rect2 ) ) return SOUTH;
if ( NSMinX( rect1 ) > NSMinX( rect2 ) && NSMaxX( rect1 ) > NSMaxX( rect2 ) ) return EAST;
return WITHIN;
}
to keep things simple i only took into account four sides. a ball hitting a corner was taken care of by giving on side (e.g. NORTH) higher priority. this, however, has the side effect of balls sometime passing through the bricks if hitting them from the side. the solution i could come up with was adding 4 more sides, i.e. the corners. hitting a corner would be interpreted as hitting a hitting a slanting side with an angle of 45°. after discussing the topic with a friend he recomended the same thing and volunteered to write the code.
int collides( NSRect rect1, NSRect rect2 ) {
if ( !NSIntersectsRect( rect1, rect2 ) ) return NONE;
int side = WITHIN;
if ( NSMinY( rect1 ) < NSMinY( rect2 ) && NSMaxY( rect1 ) < NSMaxY( rect2 ) ) {
side = NORTH;
}
if ( NSMinY( rect1 ) > NSMinY( rect2 ) && NSMaxY( rect1 ) > NSMaxY( rect2 ) ) {
side = SOUTH;
}
if ( NSMinX( rect1 ) > NSMinX( rect2 ) && NSMaxX( rect1 ) > NSMaxX( rect2 ) ) {
if ( side == NORTH ) side = NORTHEAST;
if ( side == SOUTH ) side = SOUTHEAST;
if ( side == WITHIN ) side = EAST;
}
if ( NSMinX( rect1 ) < NSMinX( rect2 ) && NSMaxX( rect1 ) < NSMaxX( rect2 ) ) {
if ( side == NORTH ) side = NORTHWEST;
if ( side == SOUTH ) side = SOUTHWEST;
if ( side == WITHIN ) side = WEST;
}
return side;
}
this didn't make things much better - possibly worse. balls would get stuck at corners, pass right through or get caugh in strange circular motions.
the last idea that we never got around to test was dividing the ball into 4 separate squares and test collision for each of them. then actions could be taken depending on which of these squares had collided. e.g. if the bottom two reported a hit we would know we had hit something straight on from above, but if only one reported a hit we would have hit a corner. the different squares wouldn't even have to hit the same object - and thus i could allow for more accuracy. i have no idea however if this might introduce any new problems.
i'll include the "collisionFrom:side withTypeOfGameObject:t" method below. please tell if you need any more information - code, screenshots or a somewhat playable demo... ;)
i'd like to discuss which collision detection i should adopt for a 2d arcade-style game i'm writing at the moment. collisions come in two distinct types: those whose effect is always the same (objects getting destroyed) and those whose effect vary depending on the objects location, speed and direction. the latter in this case is deciding upon a new direction vector for a bouncing ball (one affected by gravity).
the game area consists of 16 * 16 tiles - some are empty, others hold "bricks" of different kinds. now "balls" are to fall from above, collide and eventually come to a rest upon these bricks. the balls all have different behaviours which, among other things, affect their movement. thus i need to check what side of the brick the ball has hit (and the direction of the ball).
both balls and bricks have a rectangle bounding box (although that can easily change). what my first collision code did was essentially to check the location of the ball compared to the brick. e.g. if the ball struck the brick from above and the direction is negative (downwards), i have a collision and have simply to multiply the y-value by -0.9 (or whatever). each ball is allowed to collide only once during each engine tick. also a collision turns of some of the special behaviour (like always moving in the direction of the player) during that engine tick.
int collides( NSRect rect1, NSRect rect2 ) {
if ( !NSIntersectsRect( rect1, rect2 ) ) return NONE;
if ( NSMinY( rect1 ) < NSMinY( rect2 ) && NSMaxY( rect1 ) < NSMaxY( rect2 ) ) return NORTH;
if ( NSMinX( rect1 ) < NSMinX( rect2 ) && NSMaxX( rect1 ) < NSMaxX( rect2 ) ) return WEST;
if ( NSMinY( rect1 ) > NSMinY( rect2 ) && NSMaxY( rect1 ) > NSMaxY( rect2 ) ) return SOUTH;
if ( NSMinX( rect1 ) > NSMinX( rect2 ) && NSMaxX( rect1 ) > NSMaxX( rect2 ) ) return EAST;
return WITHIN;
}
to keep things simple i only took into account four sides. a ball hitting a corner was taken care of by giving on side (e.g. NORTH) higher priority. this, however, has the side effect of balls sometime passing through the bricks if hitting them from the side. the solution i could come up with was adding 4 more sides, i.e. the corners. hitting a corner would be interpreted as hitting a hitting a slanting side with an angle of 45°. after discussing the topic with a friend he recomended the same thing and volunteered to write the code.
int collides( NSRect rect1, NSRect rect2 ) {
if ( !NSIntersectsRect( rect1, rect2 ) ) return NONE;
int side = WITHIN;
if ( NSMinY( rect1 ) < NSMinY( rect2 ) && NSMaxY( rect1 ) < NSMaxY( rect2 ) ) {
side = NORTH;
}
if ( NSMinY( rect1 ) > NSMinY( rect2 ) && NSMaxY( rect1 ) > NSMaxY( rect2 ) ) {
side = SOUTH;
}
if ( NSMinX( rect1 ) > NSMinX( rect2 ) && NSMaxX( rect1 ) > NSMaxX( rect2 ) ) {
if ( side == NORTH ) side = NORTHEAST;
if ( side == SOUTH ) side = SOUTHEAST;
if ( side == WITHIN ) side = EAST;
}
if ( NSMinX( rect1 ) < NSMinX( rect2 ) && NSMaxX( rect1 ) < NSMaxX( rect2 ) ) {
if ( side == NORTH ) side = NORTHWEST;
if ( side == SOUTH ) side = SOUTHWEST;
if ( side == WITHIN ) side = WEST;
}
return side;
}
this didn't make things much better - possibly worse. balls would get stuck at corners, pass right through or get caugh in strange circular motions.
the last idea that we never got around to test was dividing the ball into 4 separate squares and test collision for each of them. then actions could be taken depending on which of these squares had collided. e.g. if the bottom two reported a hit we would know we had hit something straight on from above, but if only one reported a hit we would have hit a corner. the different squares wouldn't even have to hit the same object - and thus i could allow for more accuracy. i have no idea however if this might introduce any new problems.
i'll include the "collisionFrom:side withTypeOfGameObject:t" method below. please tell if you need any more information - code, screenshots or a somewhat playable demo... ;)