//Handles checking of collision with mouse and geometry and applying force on collision void TestApplication::checkMouseCollision() { for (size_t i = 0; i < _circleBodies.size(); ++i) { CircleBody& body = *_circleBodies[i]; //Check if mouse collides if (_leftMouseDown) { Vector2f mouse = (_previousMousePosition + _camera.position()) * 0.01f; //Scale mouse position to world coordinates Vector2f d = mouse - body.position(); if (d.lengthSquared() < body.radius() * body.radius()) body.applyForce(_mouseForce); } } for (size_t i = 0; i < _polygonBodies.size(); ++i) { PolygonBody& body = *_polygonBodies[i]; const std::vector<Vector2f>& verts = body.verticesWorldSpace(); //Check if the polygon and mouse collide if (_leftMouseDown) { Vector2f mouse = (_previousMousePosition + _camera.position()) * 0.01f; //Scale mouse position to world coordinates Vector2f d = mouse - body.position(); if (d.lengthSquared() < body.radius() * body.radius()) { bool collides = false; for (int j = 0, k = verts.size() - 1; j < verts.size(); k = j++) { if ( ((verts[j].y > mouse.y) != (verts[k].y > mouse.y)) && (mouse.x < (verts[k].x - verts[j].x) * (mouse.y - verts[j].y) / (verts[k].y - verts[j].y) + verts[j].x)) collides = !collides; } if (collides) body.applyForce(_mouseForce); } } } }
void Polygon2f::DoShrink(float distance, list<Polygon2f*> &parentPolygons, list<Polygon2f*> &polygons) { float distance2 = sqr(distance); list<Line2f> resLines; size_t count = vertices.size(); // build list with point translations for(int i=0; i<count;i++) { Line2f l; Vector2f Na = vertices[(i-1+count)%count]; Vector2f Nb = vertices[i]; Vector2f Nc = vertices[(i+1)%count]; l.src = Nb; Vector2f V1 = (Nb-Na).getNormalized(); Vector2f V2 = (Nc-Nb).getNormalized(); Vector2f biplane = (V2 - V1).getNormalized(); if( biplane.lengthSquared() == 0 ) { biplane.x = V1.y; biplane.y = -V1.x; } float a = CalcAngleBetween(V1,V2); bool convex = V1.cross(V2) < 0; Vector2f p; if(convex) { p = Nb+biplane*distance/(cos((PI-a)*0.5f)); l.vertices.push_back(p); } else { if( a < PI*1.25 ) { p = Nb-biplane*distance/(sin(a*0.5f)); l.vertices.push_back(p); } else { p = Nb+Vector2f(V1.y, -V1.x)*distance; l.vertices.push_back(p); p = Nb-biplane*distance; l.vertices.push_back(p); p = Nb+Vector2f(V2.y, -V2.x)*distance; l.vertices.push_back(p); } } resLines.push_back(l); } Line2f::CleanOutLine(resLines, distance2); vector<Vector2f> resVectors; for(list<Line2f>::iterator lIt = resLines.begin(); lIt != resLines.end(); lIt++) { for(list<Vector2f>::iterator pIt = lIt->vertices.begin(); pIt != lIt->vertices.end(); pIt++ ) { resVectors.push_back(*pIt); } } DoAddPolygonOutline(distance, resVectors, parentPolygons, polygons); }
//We use a modified Separating Axis Test to test for polygon-circle collisions bool PolygonBody::checkCollision(CircleBody& circle, Collision& collision) { float radiusSum = _radius + circle.radius(); if ((circle.position() - _position).lengthSquared() > radiusSum * radiusSum) return false; std::vector<Vector2f> axes; this->calculateNormals(axes); //We need the axis from the center of the circle to the closest vertex on the polygon Vector2f additionalAxis = _verticesWorldSpace[0] - circle.position(); for (size_t i = 1; i < _verticesWorldSpace.size(); ++i) { Vector2f v = _verticesWorldSpace[i] - circle.position(); if (v.lengthSquared() < additionalAxis.lengthSquared()) additionalAxis = v; } additionalAxis.normalize(); axes.push_back(additionalAxis); float minOverlap = std::numeric_limits<float>::max(); Vector2f minOverlapAxis; for (size_t i = 0; i < axes.size(); ++i) { Vector2f& axis = axes[i]; float projection = axis.dotProduct(_verticesWorldSpace.front()); float aMinProjection = projection; float aMaxProjection = projection; for (size_t j = 1; j < _verticesWorldSpace.size(); ++j) { projection = axis.dotProduct(_verticesWorldSpace[j]); aMinProjection = std::min(aMinProjection, projection); aMaxProjection = std::max(aMaxProjection, projection); } projection = axis.dotProduct(circle.position()); float bMinProjection = projection - circle.radius(); float bMaxProjection = projection + circle.radius(); if (bMinProjection > bMaxProjection) std::swap(bMinProjection, bMaxProjection); if ((aMaxProjection < bMinProjection) || (bMaxProjection < aMinProjection)) return false; //This axis has no overlap, a collision is not possible float lowerOverlap = aMaxProjection - bMinProjection; float upperOverlap = bMaxProjection - aMinProjection; if (lowerOverlap < minOverlap) { minOverlap = lowerOverlap; minOverlapAxis = axis; } if (upperOverlap < minOverlap) { minOverlap = upperOverlap; minOverlapAxis = -axis; } } collision.bodyA = this; collision.bodyB = &circle; collision.normal = minOverlapAxis; collision.depth = minOverlap; collision.contactPoints.push_back(circle.position() - collision.normal * (circle.radius() - collision.depth)); return true; }