Added collision detection for rotated rectangles.
This commit is contained in:
parent
db3bf60b2c
commit
16ad937c57
2 changed files with 18 additions and 15 deletions
|
@ -31,58 +31,60 @@ bool
|
||||||
CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
||||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||||
sf::Vector2f halfSize = rect.getSize() / 2.0f;
|
sf::Vector2f halfSize = rect.getSize() / 2.0f;
|
||||||
sf::Vector2f circleNewPos = circle.getPosition() + offsetFirst;
|
|
||||||
sf::Vector2f rectNewPos = rect.getPosition() + offsetSecond;
|
sf::Vector2f rectNewPos = rect.getPosition() + offsetSecond;
|
||||||
|
sf::Vector2f circleRotatedPos = circle.getPosition() + offsetFirst - rectNewPos;
|
||||||
|
circleRotatedPos = thor::rotatedVector(circleRotatedPos, -rect.mShape.getRotation());
|
||||||
|
circleRotatedPos += rectNewPos;
|
||||||
|
|
||||||
// If circle center is inside rect on x plane, we just take y direction result.
|
// If circle center is inside rect on x plane, we just take y direction result.
|
||||||
if (Interval::IntervalFromRadius(rectNewPos.x, halfSize.x)
|
if (Interval::IntervalFromRadius(rectNewPos.x, halfSize.x)
|
||||||
.isInside(circleNewPos.x)) {
|
.isInside(circleRotatedPos.x)) {
|
||||||
float overlapY =
|
float overlapY =
|
||||||
Interval::IntervalFromRadius(circleNewPos.y, circle.getRadius())
|
Interval::IntervalFromRadius(circleRotatedPos.y, circle.getRadius())
|
||||||
.getOverlap(Interval::IntervalFromRadius(rectNewPos.y, halfSize.y))
|
.getOverlap(Interval::IntervalFromRadius(rectNewPos.y, halfSize.y))
|
||||||
.getLength();
|
.getLength();
|
||||||
offsetFirst.y += (circleNewPos.y > rectNewPos.y)
|
offsetFirst += ((circleRotatedPos.y > rectNewPos.y) ? 1.0f : - 1.0f) *
|
||||||
? overlapY : - overlapY;
|
thor::rotatedVector(sf::Vector2f(0, overlapY), rect.mShape.getRotation());
|
||||||
return overlapY > 0;
|
return overlapY > 0;
|
||||||
}
|
}
|
||||||
// Same here (just switched x/y).
|
// Same here (just switched x/y).
|
||||||
else if (Interval::IntervalFromRadius(rectNewPos.y, halfSize.y)
|
else if (Interval::IntervalFromRadius(rectNewPos.y, halfSize.y)
|
||||||
.isInside(circleNewPos.y)) {
|
.isInside(circleRotatedPos.y)) {
|
||||||
float overlapX =
|
float overlapX =
|
||||||
Interval::IntervalFromRadius(circleNewPos.x, circle.getRadius())
|
Interval::IntervalFromRadius(circleRotatedPos.x, circle.getRadius())
|
||||||
.getOverlap(Interval::IntervalFromRadius(rectNewPos.x, halfSize.x))
|
.getOverlap(Interval::IntervalFromRadius(rectNewPos.x, halfSize.x))
|
||||||
.getLength();
|
.getLength();
|
||||||
offsetFirst.x += (circleNewPos.x > rectNewPos.x)
|
offsetFirst += ((circleRotatedPos.x > rectNewPos.x) ? 1.0f : - 1.0f) *
|
||||||
? overlapX : - overlapX;
|
thor::rotatedVector(sf::Vector2f(overlapX, 0), rect.mShape.getRotation());
|
||||||
return overlapX > 0;
|
return overlapX > 0;
|
||||||
}
|
}
|
||||||
// Test if the circle is colliding with a corner of the rectangle, using
|
// Test if the circle is colliding with a corner of the rectangle, using
|
||||||
// the same method as circle-circle collision (distance to corner instead
|
// the same method as circle-circle collision (distance to corner instead
|
||||||
// of radius.
|
// of radius.
|
||||||
else {
|
else {
|
||||||
sf::Vector2f axis(thor::unitVector(rectNewPos - circleNewPos));
|
sf::Vector2f axis(thor::unitVector(rectNewPos - circleRotatedPos));
|
||||||
|
|
||||||
// Use correct vector for corner projections (positive/negative
|
// Use correct vector for corner projections (positive/negative
|
||||||
// direction does not matter).
|
// direction does not matter).
|
||||||
float rectHalfSizeProjected;
|
float rectHalfSizeProjected;
|
||||||
if ((circleNewPos.x > rectNewPos.x && circleNewPos.y > rectNewPos.y) ||
|
if ((circleRotatedPos.x > rectNewPos.x && circleRotatedPos.y > rectNewPos.y) ||
|
||||||
(circleNewPos.x < rectNewPos.x && circleNewPos.y < rectNewPos.y))
|
(circleRotatedPos.x < rectNewPos.x && circleRotatedPos.y < rectNewPos.y))
|
||||||
rectHalfSizeProjected = thor::dotProduct(axis, halfSize);
|
rectHalfSizeProjected = thor::dotProduct(axis, halfSize);
|
||||||
else
|
else
|
||||||
rectHalfSizeProjected = thor::dotProduct(axis,
|
rectHalfSizeProjected = thor::dotProduct(axis,
|
||||||
sf::Vector2f(halfSize.x, -halfSize.y));
|
sf::Vector2f(halfSize.x, -halfSize.y));
|
||||||
|
|
||||||
Interval projectedCircle = Interval::IntervalFromRadius(
|
Interval projectedCircle = Interval::IntervalFromRadius(
|
||||||
thor::dotProduct(axis, circleNewPos),
|
thor::dotProduct(axis, circleRotatedPos),
|
||||||
circle.getRadius());
|
circle.getRadius());
|
||||||
Interval projectedRect = Interval::IntervalFromRadius(
|
Interval projectedRect = Interval::IntervalFromRadius(
|
||||||
thor::dotProduct(axis, rectNewPos),
|
thor::dotProduct(axis, rectNewPos),
|
||||||
rectHalfSizeProjected);
|
rectHalfSizeProjected);
|
||||||
// using -5: works perfectly going between corner/side
|
// using -5: works perfectly going between corner/side
|
||||||
// without -5 works perfectly on corner, but skips when going in between
|
// without -5 works perfectly on corner, but skips when going in between tiles
|
||||||
float overlap = projectedCircle.getOverlap(projectedRect).getLength() - 5;
|
float overlap = projectedCircle.getOverlap(projectedRect).getLength() - 5;
|
||||||
if (overlap > 0)
|
if (overlap > 0)
|
||||||
offsetFirst -= overlap * axis;
|
offsetFirst -= thor::rotatedVector(overlap * axis, rect.mShape.getRotation());
|
||||||
return overlap > 0;
|
return overlap > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ protected:
|
||||||
void setPosition(const sf::Vector2f& position);
|
void setPosition(const sf::Vector2f& position);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class CollisionModel;
|
||||||
friend class World;
|
friend class World;
|
||||||
|
|
||||||
sf::RectangleShape mShape;
|
sf::RectangleShape mShape;
|
||||||
|
|
Reference in a new issue