void QuadTree::draw(Core::Engine& engine){ glm::vec4 farbe(0,0,0,0); if(level_ == 0){ farbe = glm::vec4(0,0,0,1); } else if(level_ == 1){ farbe = glm::vec4(0,0,255,1); } else if(level_ == 2){ farbe = glm::vec4(255,0,0,1); } else if(level_ == 3){ farbe = glm::vec4(0,255,0,1); } else if(level_ == 4){ farbe = glm::vec4(255,255,0,1); } if(nodes_.size() > 0){ for(int i = 0; i < nodes_.size(); ++i){ nodes_.at(i)->draw(engine); } } engine.renderSystem().renderPrimitive(EL_STROKE_QUAD, glm::vec2(bounds_.x, bounds_.y), glm::vec2(bounds_.w, bounds_.h), farbe, 0); for(int i = 0; i < collisionBoxes_.size(); ++i){ CollisionBox *cb = collisionBoxes_.at(i); Util::Struct::FloatRect bounds = cb->bounds(); engine.renderSystem().renderPrimitive(EL_STROKE_QUAD, glm::vec2(cb->parent().parent().pos().x + bounds.x, cb->parent().parent().pos().y + bounds.y), glm::vec2(bounds.w, bounds.h), farbe, 0); } }
precision CollisionBox::projectToAxis(CollisionBox b, const Vector& axis) { // Find all the component contributions in the direction of // the given axis return (b.halfLength.x * std::abs(b.getAxis(0).scalarProduct(axis))) + (b.halfLength.y * std::abs(b.getAxis(1).scalarProduct(axis)))+ (b.halfLength.z * std::abs(b.getAxis(2).scalarProduct(axis))); }
static inline real transformToAxis( const CollisionBox &box, const Vector3 &axis ) { return box.halfSize.x * real_abs(axis * box.getAxis(0)) + box.halfSize.y * real_abs(axis * box.getAxis(1)) + box.halfSize.z * real_abs(axis * box.getAxis(2)); }
// TODO: Test! // REALLY TODO: TEST. There definitely is a bug in here. void CollisionSphere::genContactsB(const CollisionBox& b, std::vector<std::shared_ptr<IContact>>& o) const { // Get the sphere position in local coordinates of the box. Vect3 transformedSpherePosition = b.getTransformMatrix().getInverse() * this->getPos(); // If the sphere is further away than the magnitude of the furthest distance // a corner can be, early out: if (transformedSpherePosition.squareMagnitude() > b.getSize().squareMagnitude()) return; // Otherwise, find the closest point on the cube. // For any axis, it will be the cube half length on that side if // the sphere's position is further than the half length. If not, it'll // just be the component on that side. Vect3 closestBoxPoint = transformedSpherePosition; closestBoxPoint._x = CLAMP(closestBoxPoint._x, -b.getSize()._x, b.getSize()._x); closestBoxPoint._y = CLAMP(closestBoxPoint._y, -b.getSize()._y, b.getSize()._y); closestBoxPoint._z = CLAMP(closestBoxPoint._z, -b.getSize()._z, b.getSize()._z); // Now we have the closest point on the box. // If it's closer than the radius, we have a contact if ((closestBoxPoint - transformedSpherePosition).squareMagnitude() < this->getRadius() * this->getRadius() && ((closestBoxPoint - transformedSpherePosition).squareMagnitude() > 0.f)) { // Box contact data: Contact is under the surface of the sphere, pointing directly out. Vect3Normal d = (closestBoxPoint - transformedSpherePosition); Vect3 collisionPoint_l = transformedSpherePosition + d * _radius; Vect3 penetration_l = closestBoxPoint - collisionPoint_l; Vect3 collisionPoint_w = b.getTransformMatrix() * collisionPoint_l; Vect3 penetration_w = b.getTransformMatrix().transformDirn(penetration_l); /*Vect3 collisionPoint_l = (Vect3Normal(closestBoxPoint - this->GetPos()) * this->GetRadius()) + this->GetPos(); Vect3 collisionPoint_w = b.GetTransformMatrix() * (closestBoxPoint - transformedSpherePosition); Vect3 penetration_w = (Vect3Normal(collisionPoint_w - this->GetPos()) * this->GetRadius()) - collisionPoint_w;*/ o.push_back(this->summonDemons( collisionPoint_w, penetration_w, penetration_w.magnitude(), b.getAttachedObjectPtr(), _attachedObject)); // Sphere contact data: Exact opposite of the box contact. penetration_w *= -1.f; o.push_back(this->summonDemons( collisionPoint_w, penetration_w, penetration_w.magnitude(), this->getAttachedObjectPtr(), b.getAttachedObjectPtr())); } }
unsigned CollisionDetector::boxAndPoint( const CollisionBox &box, const Vector3 &point, CollisionData *data ) { // Transform the point into box coordinates Vector3 relPt = box.transform.transformInverse(point); Vector3 normal; // Check each axis, looking for the axis on which the // penetration is least deep. real min_depth = box.halfSize.x - real_abs(relPt.x); if (min_depth < 0) return 0; normal = box.getAxis(0) * ((relPt.x < 0)?-1:1); real depth = box.halfSize.y - real_abs(relPt.y); if (depth < 0) return 0; else if (depth < min_depth) { min_depth = depth; normal = box.getAxis(1) * ((relPt.y < 0)?-1:1); } depth = box.halfSize.z - real_abs(relPt.z); if (depth < 0) return 0; else if (depth < min_depth) { min_depth = depth; normal = box.getAxis(2) * ((relPt.z < 0)?-1:1); } // Compile the contact Contact* contact = data->contacts; contact->contactNormal = normal; contact->contactPoint = point; contact->penetration = min_depth; // Note that we don't know what rigid body the point // belongs to, so we just use NULL. Where this is called // this value can be left, or filled in. contact->setBodyData(box.body, NULL, data->friction, data->restitution); data->addContacts(1); return 1; }
bool CollisionBox::didCollide(const CollisionBox& b) const { vec3 v1=b.getPoint1()-this->getPoint2(); vec3 v2=b.getPoint2()-this->getPoint1(); if((v1.x>0)!=(v2.x>0)){ if((v1.y>0)!=(v2.y>0)){ if((v1.z>0)!=(v2.z>0)){ //std::cout<<"TEST"<<std::endl; return true; } } } return false; }
/** * Checks if two collidables intersects with each other * */ bool CollisionBox::Intersects(const CollisionBox& other) { Vector3D<float>* otherPos = other.GetPosition(); Vector3D<float>& otherBounds = other.GetBounds(); if( _LeftCollision(otherPos, otherBounds) && _RightCollision(otherPos, otherBounds) && _TopCollision(otherPos, otherBounds) && _BottomCollision(otherPos, otherBounds) && _FrontCollision(otherPos, otherBounds) && _BackCollision(otherPos, otherBounds) ) { return true; } return false; }
void fillPointFaceBoxBox( const CollisionBox &one, const CollisionBox &two, const Vector3 &toCentre, CollisionData *data, unsigned best, real pen ) { // This method is called when we know that a vertex from // box two is in contact with box one. Contact* contact = data->contacts; // We know which axis the collision is on (i.e. best), // but we need to work out which of the two faces on // this axis. Vector3 normal = one.getAxis(best); if (one.getAxis(best) * toCentre > 0) { normal = normal * -1.0f; } // Work out which vertex of box two we're colliding with. // Using toCentre doesn't work! Vector3 vertex = two.halfSize; if (two.getAxis(0) * normal < 0) vertex.x = -vertex.x; if (two.getAxis(1) * normal < 0) vertex.y = -vertex.y; if (two.getAxis(2) * normal < 0) vertex.z = -vertex.z; // Create the contact data contact->contactNormal = normal; contact->penetration = pen; contact->contactPoint = two.getTransform() * vertex; contact->setBodyData(one.body, two.body, data->friction, data->restitution); }
bool IntersectionTests::boxAndHalfSpace( const CollisionBox &box, const CollisionPlane &plane ) { // Work out the projected radius of the box onto the plane direction real projectedRadius = transformToAxis(box, plane.direction); // Work out how far the box is from the origin real boxDistance = plane.direction * box.getAxis(3) - projectedRadius; // Check for the intersection return boxDistance <= plane.offset; }
bool CollisionSphere::isTouchingB(const CollisionBox& b) const { // Get the sphere position in local coordinates of the box. Vect3 transformedSpherePosition = b.getTransformMatrix().getInverse() * this->getPos(); // If the sphere is further away than the magnitude of the furthest distance // a corner can be, early out: if (transformedSpherePosition.squareMagnitude() > b.getSize().squareMagnitude()) return false; // Otherwise, find the closest point on the cube. // For any axis, it will be the cube half length on that side if // the sphere's position is further than the half length. If not, it'll // just be the component on that side. Vect3 closestBoxPoint = transformedSpherePosition; closestBoxPoint._x = CLAMP(closestBoxPoint._x, -b.getSize()._x, b.getSize()._x); closestBoxPoint._y = CLAMP(closestBoxPoint._y, -b.getSize()._y, b.getSize()._y); closestBoxPoint._z = CLAMP(closestBoxPoint._z, -b.getSize()._z, b.getSize()._z); // Now we have the closest points on the box. // If it's closer than the radius, we have a contact. return ((closestBoxPoint - transformedSpherePosition).squareMagnitude() <= this->getRadius() * this->getRadius()); }
unsigned CollisionDetector::boxAndBox( const CollisionBox &one, const CollisionBox &two, CollisionData *data ) { //if (!IntersectionTests::boxAndBox(one, two)) return 0; // Find the vector between the two centres Vector3 toCentre = two.getAxis(3) - one.getAxis(3); // We start assuming there is no contact real pen = REAL_MAX; unsigned best = 0xffffff; // Now we check each axes, returning if it gives us // a separating axis, and keeping track of the axis with // the smallest penetration otherwise. CHECK_OVERLAP(one.getAxis(0), 0); CHECK_OVERLAP(one.getAxis(1), 1); CHECK_OVERLAP(one.getAxis(2), 2); CHECK_OVERLAP(two.getAxis(0), 3); CHECK_OVERLAP(two.getAxis(1), 4); CHECK_OVERLAP(two.getAxis(2), 5); // Store the best axis-major, in case we run into almost // parallel edge collisions later unsigned bestSingleAxis = best; CHECK_OVERLAP(one.getAxis(0) % two.getAxis(0), 6); CHECK_OVERLAP(one.getAxis(0) % two.getAxis(1), 7); CHECK_OVERLAP(one.getAxis(0) % two.getAxis(2), 8); CHECK_OVERLAP(one.getAxis(1) % two.getAxis(0), 9); CHECK_OVERLAP(one.getAxis(1) % two.getAxis(1), 10); CHECK_OVERLAP(one.getAxis(1) % two.getAxis(2), 11); CHECK_OVERLAP(one.getAxis(2) % two.getAxis(0), 12); CHECK_OVERLAP(one.getAxis(2) % two.getAxis(1), 13); CHECK_OVERLAP(one.getAxis(2) % two.getAxis(2), 14); // Make sure we've got a result. assert(best != 0xffffff); // We now know there's a collision, and we know which // of the axes gave the smallest penetration. We now // can deal with it in different ways depending on // the case. if (best < 3) { // We've got a vertex of box two on a face of box one. fillPointFaceBoxBox(one, two, toCentre, data, best, pen); data->addContacts(1); return 1; } else if (best < 6) { // We've got a vertex of box one on a face of box two. // We use the same algorithm as above, but swap around // one and two (and therefore also the vector between their // centres). fillPointFaceBoxBox(two, one, toCentre*-1.0f, data, best-3, pen); data->addContacts(1); return 1; } else { // We've got an edge-edge contact. Find out which axes best -= 6; unsigned oneAxisIndex = best / 3; unsigned twoAxisIndex = best % 3; Vector3 oneAxis = one.getAxis(oneAxisIndex); Vector3 twoAxis = two.getAxis(twoAxisIndex); Vector3 axis = oneAxis % twoAxis; axis.normalise(); // The axis should point from box one to box two. if (axis * toCentre > 0) axis = axis * -1.0f; // We have the axes, but not the edges: each axis has 4 edges parallel // to it, we need to find which of the 4 for each object. We do // that by finding the point in the centre of the edge. We know // its component in the direction of the box's collision axis is zero // (its a mid-point) and we determine which of the extremes in each // of the other axes is closest. Vector3 ptOnOneEdge = one.halfSize; Vector3 ptOnTwoEdge = two.halfSize; for (unsigned i = 0; i < 3; i++) { if (i == oneAxisIndex) ptOnOneEdge[i] = 0; else if (one.getAxis(i) * axis > 0) ptOnOneEdge[i] = -ptOnOneEdge[i]; if (i == twoAxisIndex) ptOnTwoEdge[i] = 0; else if (two.getAxis(i) * axis < 0) ptOnTwoEdge[i] = -ptOnTwoEdge[i]; } // Move them into world coordinates (they are already oriented // correctly, since they have been derived from the axes). ptOnOneEdge = one.transform * ptOnOneEdge; ptOnTwoEdge = two.transform * ptOnTwoEdge; // So we have a point and a direction for the colliding edges. // We need to find out point of closest approach of the two // line-segments. Vector3 vertex = contactPoint( ptOnOneEdge, oneAxis, one.halfSize[oneAxisIndex], ptOnTwoEdge, twoAxis, two.halfSize[twoAxisIndex], bestSingleAxis > 2 ); // We can fill the contact. Contact* contact = data->contacts; contact->penetration = pen; contact->contactNormal = axis; contact->contactPoint = vertex; contact->setBodyData(one.body, two.body, data->friction, data->restitution); data->addContacts(1); return 1; } return 0; }
bool CollisionBox::earlyOut(CollisionBox b1, CollisionBox b2) { Vector centre = b2.centre - b1.centre; return !( overlaps(b1, b2, b1.getAxis(0)) && overlaps(b1, b2, b1.getAxis(1)) && overlaps(b1, b2, b1.getAxis(2)) && overlaps(b1, b2, b2.getAxis(0)) && overlaps(b1, b2, b2.getAxis(1)) && overlaps(b1, b2, b2.getAxis(2)) && overlaps(b1, b2, b1.getAxis(0) % b2.getAxis(0)) && overlaps(b1, b2, b1.getAxis(0) % b2.getAxis(1)) && overlaps(b1, b2, b1.getAxis(0) % b2.getAxis(2)) && overlaps(b1, b2, b1.getAxis(1) % b2.getAxis(0)) && overlaps(b1, b2, b1.getAxis(1) % b2.getAxis(1)) && overlaps(b1, b2, b1.getAxis(1) % b2.getAxis(2)) && overlaps(b1, b2, b1.getAxis(2) % b2.getAxis(0)) && overlaps(b1, b2, b1.getAxis(2) % b2.getAxis(1)) && overlaps(b1, b2, b1.getAxis(2) % b2.getAxis(2)) ); }
bool CollisionBox::isZCollision(const CollisionBox &box) { return !(_max(2) < box.getMinZ() || box.getMaxZ() < _min(2)); }
bool CollisionBox::isXCollision(const CollisionBox &box) { return !(_max(0) < box.getMinX() || box.getMaxX() < _min(0)); }
bool Monster::checkBoxes(std::vector<CollisionBox>* boxes, float p_x, float p_y){ CollisionBox box; Point2D A = Point2D(this->getX(), this->getY()); Point2D B; for (int i = 0; i < boxes->size(); i++){ box = boxes->at(i); if (box.getRight() < this->getBox().getLeft()) B.setX(box.getRight()); else if (box.getLeft() > this->getBox().getRight()) B.setX(box.getLeft()); else B.setX(this->getX()); if (box.getTop() < this->getBox().getBottom()) B.setY(box.getTop()); else if (box.getBottom() > this->getBox().getTop()) B.setY(box.getBottom()); else B.setY(this->getY()); float difx = (B.getX() - A.getX()) * (B.getX() - A.getX()); float dify = (B.getY() - A.getY()) * (B.getY() - A.getY()); float dist = difx + dify; if (dist <= this->getRadius() * this->getRadius()){ if ((this->getBox().getBottom() > box.getTop() || this->getBox().getTop() < box.getBottom()) ){ if (this->getBox().getBottom() > box.getTop()){ if (p_x == this->getX()){ this->angle = 0; } else if (p_x > this->getX()){ if (this->getY() < p_y) this->angle = 8; else this->angle = 0; } else { if (this->getY() < p_y) this->angle = 172; else this->angle = 180; } } else if (this->getBox().getTop() < box.getBottom()){ if (p_x == this->getX()){ this->angle = 0; } else if (p_x > this->getX()){ if (this->getY() > p_y) this->angle = 352; else this->angle = 0; } else{ if (this->getY() > p_y) this->angle = 188; else this->angle = 180; } } } else if ((this->getBox().getRight() < box.getLeft() || this->getBox().getLeft() > box.getRight()) ){ float up = box.getTop() - this->getY(); float down = this->getY() - box.getBottom(); if (this->getBox().getRight() < box.getLeft()){ if (p_y == this->getY()){ this->angle = 90; } else if (p_y > this->getY()){ if (this->getX() > p_x) this->turn(this->getX() - 16, box.getTop() + 32); else this->turn(this->getX(), box.getTop() + 32); } else{ if (this->getX() > p_x) this->turn(this->getX() - 16, box.getBottom() - 32); else this->turn(this->getX(), box.getBottom() - 32); } } else if (this->getBox().getLeft() > box.getRight()){ if (p_y == this->getY()){ this->angle = 90; } else if (p_y > this->getY()){ if (this->getX() < p_x) this->turn(this->getX() + 16, box.getTop() + 32); else this->turn(this->getX(), box.getTop() + 32); } else{ if (this->getX() < p_x) this->turn(this->getX() + 16, box.getBottom() - 32); else this->turn(this->getX(), box.getBottom() - 32); } } } return true; } else continue; } return false; }
bool IntersectionTests::boxAndBox( const CollisionBox &one, const CollisionBox &two ) { // Find the vector between the two centres Vector3 toCentre = two.getAxis(3) - one.getAxis(3); return ( // Check on box one's axes first TEST_OVERLAP(one.getAxis(0)) && TEST_OVERLAP(one.getAxis(1)) && TEST_OVERLAP(one.getAxis(2)) && // And on two's TEST_OVERLAP(two.getAxis(0)) && TEST_OVERLAP(two.getAxis(1)) && TEST_OVERLAP(two.getAxis(2)) && // Now on the cross products TEST_OVERLAP(one.getAxis(0) % two.getAxis(0)) && TEST_OVERLAP(one.getAxis(0) % two.getAxis(1)) && TEST_OVERLAP(one.getAxis(0) % two.getAxis(2)) && TEST_OVERLAP(one.getAxis(1) % two.getAxis(0)) && TEST_OVERLAP(one.getAxis(1) % two.getAxis(1)) && TEST_OVERLAP(one.getAxis(1) % two.getAxis(2)) && TEST_OVERLAP(one.getAxis(2) % two.getAxis(0)) && TEST_OVERLAP(one.getAxis(2) % two.getAxis(1)) && TEST_OVERLAP(one.getAxis(2) % two.getAxis(2)) ); }
bool CollisionBox::isXZCollision(const CollisionBox &box) { return !(maxX < box.getMinX() || box.getMaxX() < minX || maxZ < box.getMinZ() || box.getMaxZ() < minZ); }