//============================================================================= // Rotated Box and Circle collision detection method // Called by collision() // Uses separating axis test on edges of box and radius of circle. // If the circle center is outside the lines extended from the collision box // edges (also known as the Voronoi region) then the nearest box corner is checked // for collision using a distance check. // The nearest corner is determined from the overlap tests. // // Voronoi0 | | Voronoi1 // ---0---1--- // | | // ---3---2--- // Voronoi3 | | Voronoi2 // // Pre: This entity must be box and other entity (ent) must be circle. // Post: returns true if collision, false otherwise // sets collisionVector if collision //============================================================================= bool Entity::collideRotatedBoxCircle(Entity &ent, VECTOR2 &collisionVector) { float min01, min03, max01, max03, center01, center03; computeRotatedBox(); // prepare rotated box // project circle center onto edge01 center01 = graphics->Vector2Dot(&edge01, ent.getCenter()); min01 = center01 - ent.getRadius()*ent.getScale(); // min and max are Radius from center max01 = center01 + ent.getRadius()*ent.getScale(); if (min01 > edge01Max || max01 < edge01Min) // if projections do not overlap return false; // no collision is possible // project circle center onto edge03 center03 = graphics->Vector2Dot(&edge03, ent.getCenter()); min03 = center03 - ent.getRadius()*ent.getScale(); // min and max are Radius from center max03 = center03 + ent.getRadius()*ent.getScale(); if (min03 > edge03Max || max03 < edge03Min) // if projections do not overlap return false; // no collision is possible // circle projection overlaps box projection // check to see if circle is in voronoi region of collision box if(center01 < edge01Min && center03 < edge03Min) // if circle in Voronoi0 return collideCornerCircle(corners[0], ent, collisionVector); if(center01 > edge01Max && center03 < edge03Min) // if circle in Voronoi1 return collideCornerCircle(corners[1], ent, collisionVector); if(center01 > edge01Max && center03 > edge03Max) // if circle in Voronoi2 return collideCornerCircle(corners[2], ent, collisionVector); if(center01 < edge01Min && center03 > edge03Max) // if circle in Voronoi3 return collideCornerCircle(corners[3], ent, collisionVector); // circle not in voronoi region so it is colliding with edge of box // set collision vector, uses simple center of circle to center of box collisionVector = *ent.getCenter() - *getCenter(); return true; }
//============================================================================= // Rotated Box and Circle collision detection method // Called by collision() // Uses separating axis test on edges of box and radius of circle. // If the circle center is outside the lines extended from the collision box // edges (also known as the Voronoi region) then the nearest box corner is checked // for collision using a distance check. // The nearest corner is determined from the overlap tests. // // Voronoi0 | | Voronoi1 // ---0---1--- // | | // ---3---2--- // Voronoi3 | | Voronoi2 // // Pre: This entity must be rotated box and other entity (ent) must be circle. // Post: returns true if collision, false otherwise // sets collisionVector if collision //============================================================================= bool Entity::collideRotatedBoxCircle(Entity &ent, VECTOR2 &collisionVector) { float min01, min03, max01, max03, center01, center03, minOverlap, minOverlap2; computeRotatedBox(); // prepare rotated box // project circle center onto edge01 center01 = graphics->Vector2Dot(&edge01, ent.getCenter()); min01 = center01 - ent.getRadius()*ent.getScale(); // min and max are Radius from center max01 = center01 + ent.getRadius()*ent.getScale(); if (min01 > edge01Max || max01 < edge01Min) // if projections do not overlap return false; // no collision is possible // project circle center onto edge03 center03 = graphics->Vector2Dot(&edge03, ent.getCenter()); min03 = center03 - ent.getRadius()*ent.getScale(); // min and max are Radius from center max03 = center03 + ent.getRadius()*ent.getScale(); if (min03 > edge03Max || max03 < edge03Min) // if projections do not overlap return false; // no collision is possible // circle projection overlaps box projection // check to see if circle is in voronoi region of collision box if(center01 < edge01Min && center03 < edge03Min) // if circle in Voronoi0 return collideCornerCircle(corners[0], ent, collisionVector); if(center01 > edge01Max && center03 < edge03Min) // if circle in Voronoi1 return collideCornerCircle(corners[1], ent, collisionVector); if(center01 > edge01Max && center03 > edge03Max) // if circle in Voronoi2 return collideCornerCircle(corners[2], ent, collisionVector); if(center01 < edge01Min && center03 > edge03Max) // if circle in Voronoi3 return collideCornerCircle(corners[3], ent, collisionVector); // Circle not in voronoi region so it is colliding with edge of box // The edge with the smallest overlapping section is the edge where // the collision is occuring. The collision vector is created perpendicular // to the collision edge. // min01, min03, max01, max03 are the projection limits for one object and // edge01Min, edge01Max, edge03Min, edge03Max are the projection limits // for the other object. This code was contributed to the programming2dgames // forum by user stbn. The technique is described at // www.metanetsoftware.com/technique/tutorialA.html if (min01 < edge01Min) { minOverlap = max01 - edge01Min; collisionVector = corners[1] - corners[0]; collisionCenter = corners[0]; ent.setCollisionCenter(corners[1]); } else { minOverlap = edge01Max - min01; collisionVector = corners[0] - corners[1]; collisionCenter = corners[1]; ent.setCollisionCenter(corners[0]); } if (min03 < edge03Min) { minOverlap2 = max03 - edge03Min; if (minOverlap2 < minOverlap) { collisionVector = corners[3] - corners[0]; collisionCenter = corners[0]; ent.setCollisionCenter(corners[3]); } } else { minOverlap2 = edge03Max - min03; if (minOverlap2 < minOverlap) { collisionVector = corners[0] - corners[3]; collisionCenter = corners[3]; ent.setCollisionCenter(corners[0]); } } return true; }
//============================================================================= // Rotated Box and Circle collision detection method // Called by collision() // Uses separating axis test on edges of box and radius of circle. // If the circle center is outside the lines extended from the collision box // edges (also known as the Voronoi region) then the nearest box corner is checked // for collision using a distance check. // The nearest corner is determined from the overlap tests. // // Voronoi0 | | Voronoi1 // ---0---1--- // | | // ---3---2--- // Voronoi3 | | Voronoi2 // // Pre: This entity (entA) must be rotated box and other entity (entB) must be circle. // Post: returns true if collision, false otherwise // sets collisionVector if collision //============================================================================= bool Entity::collideRotatedBoxCircle(Entity &entB, VECTOR2 &collisionVector) { float center01, center03, overlap01, overlap03; computeRotatedBox(); // prepare rotated box // project circle center onto edge01 center01 = graphics->Vector2Dot(&edge01, entB.getCenter()); entB01min = center01 - entB.getRadius()*entB.getScale(); // min and max are Radius from center entB01max = center01 + entB.getRadius()*entB.getScale(); if (entB01min > entA01max || entB01max < entA01min) // if projections do not overlap return false; // no collision is possible // project circle center onto edge03 center03 = graphics->Vector2Dot(&edge03, entB.getCenter()); entB03min = center03 - entB.getRadius()*entB.getScale(); // min and max are Radius from center entB03max = center03 + entB.getRadius()*entB.getScale(); if (entB03min > entA03max || entB03max < entA03min) // if projections do not overlap return false; // no collision is possible // circle projection overlaps box projection // check to see if circle is in voronoi region of collision box if(center01 < entA01min && center03 < entA03min) // if circle in Voronoi0 return collideCornerCircle(corners[0], entB, collisionVector); if(center01 > entA01max && center03 < entA03min) // if circle in Voronoi1 return collideCornerCircle(corners[1], entB, collisionVector); if(center01 > entA01max && center03 > entA03max) // if circle in Voronoi2 return collideCornerCircle(corners[2], entB, collisionVector); if(center01 < entA01min && center03 > entA03max) // if circle in Voronoi3 return collideCornerCircle(corners[3], entB, collisionVector); // Circle not in voronoi region so it is colliding with edge of box. // The edge with the smallest overlapping section is the edge where the // collision is occuring. The collision vector is created perpendicular // to the collision edge. The projection edges are 01 and 03. // // entA01min // / entB01min // / / entB01max // / / / entA01max // / / / / // 0--------------------1 // entB03min..| ___ // entA03min..| ___/ B \__ // entB03max..| | \___/ | // | | A | // entA03max..| |__________| // | // | // | // 3 // if (entA01min < entB01min) // if A left of B { overlap01 = entA01max - entB01min; collisionVector = corners[1] - corners[0]; } else // else, A right of B { overlap01 = entB01max - entA01min; collisionVector = corners[0] - corners[1]; } if (entA03min < entB03min) // if A above B { overlap03 = entA03max - entB03min; if (overlap03 < overlap01) collisionVector = corners[3] - corners[0]; } else // else, A below B { overlap03 = entB03max - entA03min; if (overlap03 < overlap01) collisionVector = corners[0] - corners[3]; } return true; }