protected override bool TestCollisionVsOBB(OBB_2D other, out Collision collision) { collision = null; // same as aabb // multiply circle center by box world matrix inverse //other.transform.worldToLocalMatrix Matrix4x4 otherMat = other.transform.worldToLocalMatrix; Vector2 minExtents = other.particle.position - other.halfWidths, maxExtents = other.particle.position + other.halfWidths; Vector2 adjustedCenter = otherMat.MultiplyPoint3x4(new Vector3(particle.position.x, particle.position.y, 0)); adjustedCenter.x *= other.transform.localScale.x; adjustedCenter.y *= other.transform.localScale.y; adjustedCenter += (Vector2)other.transform.position; //adjustedCenter += particle.position; Vector2 closestPoint; closestPoint.x = Mathf.Clamp(adjustedCenter.x, minExtents.x, maxExtents.x); closestPoint.y = Mathf.Clamp(adjustedCenter.y, minExtents.y, maxExtents.y); Vector2 deltaPos = adjustedCenter - closestPoint; bool colliding = deltaPos.sqrMagnitude < radius * radius; if (colliding) { collision = new Collision(); Vector2 relativeVelocity = particle.velocity - other.particle.velocity; Vector2 relativePosition = particle.position - other.particle.position; // 7.1.1 closing velocity collision.closingVelocity = Vector3.Dot(relativeVelocity, relativePosition.normalized); // assuming one point of contact collision.contact[0].normal = deltaPos.normalized; collision.contact[0].point = closestPoint; collision.contact[0].restitution = .5f; collision.contact[0].penetrationDepth = radius - deltaPos.magnitude; collision.a = this; collision.b = other; collision.status = colliding; collision.contactCount = 1; } return(colliding); }
protected override bool TestCollisionVsOBB(OBB_2D other, out Collision collision) { collision = null; // Code from Michael Zheng and Ben Strong, using with permission // same as above twice // find max extents of OBB, do ABB vs this box // then, transform this box into OBB's space, find max extents, repeat //1. create max and min extents of this particle //2. max = (center.x + length/2, center.y + height/2) //3. min = (center.x - length/2, center.y - height/2) //4. create max and min extents of other particle //4a. find all corner points of the box using length, height //4b. rotate all points around its rotation https://www.gamefromscratch.com/post/2012/11/24/GameDev-math-recipes-Rotating-one-point-around-another-point.aspx //4c. min = (min(x of all points), min(y of all points)) https://stackoverflow.com/questions/3231176/how-to-get-size-of-a-rotated-rectangle //4d. max = (max(x of all points), max(y of all points) //5. check if this_max.x > other_min.x and this_max.y > other_min.y //6. check if other_max.x > this_min.x and other_max.y > this_min.y //7. transform this center around the other's center using its transform matrix inverse //8. transform each point of the aab by the other's transform matrix inverse //8. find max and min extents of this by using Max(all points), Min(all points) //5. check if new this_max.x > other_min.x and new this_max.y > other_min.y //6. check if other_max.x > new this_min.x and other_max.y > new this_min.y //9. if all checks are true, then collision check passes bool check1, check2; Vector2 thisMax, thisMin, otherMax, otherMin; Vector2 p1, p2, p3, p4; Vector2 otherPosition = other.particle.position; float thisLength = halfWidths[0]; float thisHeight = halfWidths[1]; float otherLength = other.halfWidths[0]; float otherHeight = other.halfWidths[1]; //max and min of this position thisMax = new Vector2(particle.position.x + thisLength, particle.position.y + thisHeight); thisMin = new Vector2(particle.position.x - thisLength, particle.position.y - thisHeight); //find max and min of other //get all corner points and then rotate it //p1 = rotatePoint(new Vector2(otherLength, otherHeight), other.rotation); //p2 = rotatePoint(new Vector2(otherLength, -otherHeight), other.rotation); //p3 = rotatePoint(new Vector2(-otherLength, -otherHeight), other.rotation); //p4 = rotatePoint(new Vector2(-otherLength, otherHeight), other.rotation); p1 = other.transform.worldToLocalMatrix * (new Vector2(otherLength, otherHeight)); p2 = other.transform.worldToLocalMatrix * (new Vector2(otherLength, -otherHeight)); p3 = other.transform.worldToLocalMatrix * (new Vector2(-otherLength, -otherHeight)); p4 = other.transform.worldToLocalMatrix * (new Vector2(-otherLength, otherHeight)); //find max of all points otherMax = new Vector2(Mathf.Max(p1.x, p2.x, p3.x, p4.x) + otherPosition.x, Mathf.Max(p1.y, p2.y, p3.y, p4.y) + otherPosition.y); otherMin = new Vector2(Mathf.Min(p1.x, p2.x, p3.x, p4.x) + otherPosition.x, Mathf.Min(p1.y, p2.y, p3.y, p4.y) + otherPosition.y); check1 = (thisMax.x >= otherMin.x && thisMax.y >= otherMin.y) && (otherMax.x >= thisMin.x && otherMax.y >= thisMin.y); if (!check1) { return(false); } //for each corner, move it relative to the box then transform by the world matrix inverse. Finally add position back p1 = other.transform.worldToLocalMatrix * (new Vector2(particle.position.x + thisLength, particle.position.y + thisHeight) - otherPosition); //this one p2 = other.transform.worldToLocalMatrix * (new Vector2(particle.position.x + thisLength, particle.position.y - thisHeight) - otherPosition); p3 = other.transform.worldToLocalMatrix * (new Vector2(particle.position.x - thisLength, particle.position.y - thisHeight) - otherPosition); p4 = other.transform.worldToLocalMatrix * (new Vector2(particle.position.x - thisLength, particle.position.y + thisHeight) - otherPosition); p1 += otherPosition; p2 += otherPosition; p3 += otherPosition; p4 += otherPosition; //get the extremes for min and max thisMax = new Vector2(Mathf.Max(p1.x, p2.x, p3.x, p4.x), Mathf.Max(p1.y, p2.y, p3.y, p4.y)); thisMin = new Vector2(Mathf.Min(p1.x, p2.x, p3.x, p4.x), Mathf.Min(p1.y, p2.y, p3.y, p4.y)); otherMax = new Vector2(otherPosition.x + otherLength, otherPosition.y + otherHeight); otherMin = new Vector2(otherPosition.x - otherLength, otherPosition.y - otherHeight); check2 = (thisMax.x >= otherMin.x && thisMax.y >= otherMin.y) && (otherMax.x >= thisMin.x && otherMax.y >= thisMin.y); if (!check2) { return(false); } return(true); }
protected override bool TestCollisionVsOBB(OBB_2D other, out Collision collision) { collision = null; // Code from Michael Zheng and Ben Strong, using with permission //Transform this into others space and do AABB vs OBB //transform other into this space and do AABB vs OBB //If both tests pass, collision occurs otherwise no collision //1. do AABB check with this rotated around other //2. find all corner points of this box using length and height //3. rotate the points of this box with its rotation //4. transform the points using the transform inverse of the other //5. min = (min(x of all points), min(y of all points)) //6. max = (max(x of all points), max(y of all points) //7. create max and min extents of other particle //8. max = (center.x + length/2, center.y + height/2) //9. min = (center.x - length/2, center.y - height/2) //10. check if this_max.x > other_min.x and this_max.y > other_min.y //11. check if other_max.x > this_min.x and other_max.y > this_min.y //12. do AABB check with other rotated around this //13. find all corner points of other box using length and height //14. rotate the points of other box with its rotation //15. transform the points using the transform inverse of this //16. min = (min(x of all points), min(y of all points)) //17. max = (max(x of all points), max(y of all points) //18. create max and min extents of this particle //19. max = (center.x + length/2, center.y + height/2) //20. min = (center.x - length/2, center.y - height/2) //21. check if this_max.x > other_min.x and this_max.y > other_min.y //22. check if other_max.x > this_min.x and other_max.y > this_min.y bool check1, check2; Vector2 thisMax, thisMin, otherMax, otherMin; Vector2 p1, p2, p3, p4; Vector2 otherPosition = other.particle.position; float thisLength = halfWidths[0]; float thisHeight = halfWidths[1]; float otherLength = other.halfWidths[0]; float otherHeight = other.halfWidths[1]; //get all corner points and then rotate it p1 = transform.worldToLocalMatrix * (new Vector2(thisLength, thisHeight)); p2 = transform.worldToLocalMatrix * (new Vector2(thisLength, -thisHeight)); p3 = transform.worldToLocalMatrix * (new Vector2(-thisLength, -thisHeight)); p4 = transform.worldToLocalMatrix * (new Vector2(-thisLength, thisHeight)); //for each corner, move it relative to the box then transform by the world matrix inverse. Finally add position back p1 = other.transform.worldToLocalMatrix * (p1 + particle.position - otherPosition); p2 = other.transform.worldToLocalMatrix * (p2 + particle.position - otherPosition); p3 = other.transform.worldToLocalMatrix * (p3 + particle.position - otherPosition); p4 = other.transform.worldToLocalMatrix * (p4 + particle.position - otherPosition); p1 += otherPosition; p2 += otherPosition; p3 += otherPosition; p4 += otherPosition; thisMax = new Vector2(Mathf.Max(p1.x, p2.x, p3.x, p4.x), Mathf.Max(p1.y, p2.y, p3.y, p4.y)); thisMin = new Vector2(Mathf.Min(p1.x, p2.x, p3.x, p4.x), Mathf.Min(p1.y, p2.y, p3.y, p4.y)); otherMax = new Vector2(otherPosition.x + otherLength, otherPosition.y + otherHeight); otherMin = new Vector2(otherPosition.x - otherLength, otherPosition.y - otherHeight); check1 = (thisMax.x >= otherMin.x && thisMax.y >= otherMin.y) && (otherMax.x >= thisMin.x && otherMax.y >= thisMin.y); if (!check1) { return(false); } //get all corner points and then rotate it p1 = other.transform.worldToLocalMatrix * (new Vector2(otherLength, otherHeight)); p2 = other.transform.worldToLocalMatrix * (new Vector2(otherLength, -otherHeight)); p3 = other.transform.worldToLocalMatrix * (new Vector2(-otherLength, -otherHeight)); p4 = other.transform.worldToLocalMatrix * (new Vector2(-otherLength, otherHeight)); //for each corner, move it relative to the box then transform by the world matrix inverse. Finally add position back p1 = transform.worldToLocalMatrix * (p1 + otherPosition - particle.position); //this p2 = transform.worldToLocalMatrix * (p2 + otherPosition - particle.position); p3 = transform.worldToLocalMatrix * (p3 + otherPosition - particle.position); p4 = transform.worldToLocalMatrix * (p4 + otherPosition - particle.position); p1 += particle.position; p2 += particle.position; p3 += particle.position; p4 += particle.position; otherMax = new Vector2(Mathf.Max(p1.x, p2.x, p3.x, p4.x), Mathf.Max(p1.y, p2.y, p3.y, p4.y)); otherMin = new Vector2(Mathf.Min(p1.x, p2.x, p3.x, p4.x), Mathf.Min(p1.y, p2.y, p3.y, p4.y)); thisMax = new Vector2(particle.position.x + thisLength, particle.position.y + thisHeight); thisMin = new Vector2(particle.position.x - thisLength, particle.position.y - thisHeight); check2 = (thisMax.x >= otherMin.x && thisMax.y >= otherMin.y) && (otherMax.x >= thisMin.x && otherMax.y >= thisMin.y); if (!check2) { return(false); } return(true); }
protected abstract bool TestCollisionVsOBB(OBB_2D other, out Collision collision);