public static Collision CircleCircleIntersection(CircleCollider a, CircleCollider b) { Vector2 delta = b.gameObject.transform.position - a.gameObject.transform.position; float realRadA = a.gameObject.transform.LocalToWorldLength(a.radius); float realRadB = b.gameObject.transform.LocalToWorldLength(b.radius); float mag = delta.magnitude; if (Vector2.HasNaN(delta)) { a.gameObject.Throw("delta has nan \n " + a.gameObject.name + " apos " + a.gameObject.transform.position + "\n " + b.gameObject.name + " bpos " + b.gameObject.transform.position); } bool isincol = b.IsPointInCollider(a.gameObject.transform.position); if (mag > (realRadA + realRadB) && !isincol) { return(null); } Collision s = new Collision(); s.collider = b; s.rejection = (realRadA + realRadB - mag); if (float.IsNaN(s.rejection)) { a.gameObject.Throw("s.rejection is nan\nrealrada " + realRadA + "\nrealradb " + realRadB + "\nmag " + mag); } s.point = a.gameObject.transform.position + delta * (realRadA - s.rejection / 2) / mag; s.normal = b.GetNormal(s.point); float x = (realRadA + realRadB - mag) / 2; s.area = (float)(Math.PI * x * realRadB * Math.Sqrt(1.0 - (realRadB - x) * (realRadB - x) / realRadB / realRadB)); if (isincol) { if (float.IsNaN(s.area)) { s.area = a.area; } else { s.area = a.area - s.area; } } if (s.area == 0) { s.area = MyMath.dFloat; } return(s); }
public SteamDrop() { gameObject = new GameObject();; gameObject.AddBehaviour(this); rend = new CircleRenderer(gameObject, MyMath.dFloat); col = new CircleCollider(gameObject, 0); col.isTrigger = true; gameObject.collider = col; gameObject.renderer = rend; gameObject.rigidbody = new Rigidbody(gameObject); gameObject.rigidbody.isKinematic = false; gameObject.rigidbody.useGravity = false; }
public static Collision CircleConvexIntersection(CircleCollider a, ConvexCollider b, bool ImCircle = true) { Vector2 localPoint = b.gameObject.transform.WorldToLocalPoint(a.gameObject.transform.position); Vector2 ret = Vector2.zero; Vector2 nor = Vector2.zero; int count = 0; float area = 0; float realRadA = a.gameObject.transform.LocalToWorldLength(a.radius); float radALocalToB = b.gameObject.transform.WorldToLocalLength(realRadA); float sqrRadALocalToB = radALocalToB * radALocalToB; Vector2 a0 = localPoint - b.points [b.len - 1]; float proj0 = Vector2.Dot(a0, b.deltas[0]) / b.lengths [0]; float rej0 = Math.Abs(Vector2.Cross(a0, b.deltas [0]) / b.lengths [0]); float rejection = 0; if (rej0 <= radALocalToB && 0 <= proj0 && proj0 <= b.lengths [0]) { //ret += b.points [b.len - 1] + b.deltas [0] * MyMath.Clamp(proj0 / b.lengths [0], 0, 1); Vector2 vrej = Vector2.Reject(a0, b.deltas [0]); float vrejMag = vrej.magnitude; float worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag); float darea = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA)); nor += Vector2.Rotate(b.deltas[0].normalized, MyMath.FloatPIPer2) * darea; ret += (localPoint - vrej) * darea; area += darea; rejection = Math.Max(rejection, realRadA - worldVrejMag); count++; } else if (Vector2.SqrDistance(b.points [0], localPoint) <= sqrRadALocalToB) { count++; float y = radALocalToB - Vector2.Distance(b.points [0], localPoint); Vector2 delta = b.points [0] - localPoint; Vector2 proji = Vector2.Project(b.deltas [0], delta); Vector2 projiPlus1 = Vector2.Project(b.deltas [1], delta); Vector2 reji = b.deltas [0] - proji; Vector2 rejiPlus1 = b.deltas [1] - projiPlus1; float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude); rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude)); ret += b.points [1] * darea; nor += (Vector2.Reject(a0, b.deltas [1]) + Vector2.Reject(localPoint - b.points [0], b.deltas [1])).normalized * darea; area += darea; } for (int i = 1; i < b.len - 1; i++) { Vector2 ai = localPoint - b.points [i - 1]; float proj = Vector2.Dot(ai, b.deltas [i]) / b.lengths [i]; float rej = Math.Abs(Vector2.Cross(ai, b.deltas [i]) / b.lengths [i]); if (rej <= radALocalToB && 0 <= proj && proj <= b.lengths [i]) { Vector2 vrej = Vector2.Reject(ai, b.deltas [i]); float vrejMag = vrej.magnitude; float worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag); float darea = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA)); nor += Vector2.Rotate(b.deltas [i].normalized, MyMath.FloatPIPer2) * darea; ret += (localPoint - vrej) * darea; area += darea; rejection = Math.Max(rejection, realRadA - worldVrejMag); count++; } else if (Vector2.SqrDistance(b.points [i], localPoint) <= sqrRadALocalToB) { count++; float y = radALocalToB - Vector2.Distance(b.points [i], localPoint); Vector2 delta = b.points [i] - localPoint; Vector2 proji = Vector2.Project(b.deltas [i], delta); Vector2 projiPlus1 = Vector2.Project(b.deltas [i + 1], delta); Vector2 reji = b.deltas [i] - proji; Vector2 rejiPlus1 = b.deltas [i + 1] - projiPlus1; float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude); rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude)); ret += b.points [i] * darea; nor += (Vector2.Reject(ai, b.deltas [i]) + Vector2.Reject(localPoint - b.points [i], b.deltas [i + 1])).normalized * darea; area += darea; } } int last = b.len - 1; Vector2 al = localPoint - b.points [last - 1]; float projl = Vector2.Dot(al, b.deltas[last]) / b.lengths [last]; float rejl = Math.Abs(Vector2.Cross(al, b.deltas [last]) / b.lengths [last]); if (rejl <= radALocalToB && 0 <= projl && projl <= b.lengths [last]) { Vector2 vrej = Vector2.Reject(al, b.deltas [last]); float vrejMag = vrej.magnitude; float worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag); float darea = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA)); nor += Vector2.Rotate(b.deltas[last].normalized, MyMath.FloatPIPer2) * darea; ret += (localPoint - vrej) * darea; area += darea; rejection = Math.Max(rejection, realRadA - worldVrejMag); count++; } else if (Vector2.SqrDistance(b.points [last], localPoint) <= sqrRadALocalToB) { count++; float y = radALocalToB - Vector2.Distance(b.points [last], localPoint); Vector2 delta = b.points [last] - localPoint; Vector2 proji = Vector2.Project(b.deltas [last], delta); Vector2 projiPlus1 = Vector2.Project(b.deltas [0], delta); Vector2 reji = b.deltas [last] - proji; Vector2 rejiPlus1 = b.deltas [0] - projiPlus1; float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude); rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude)); ret += b.points [last] * darea; //nor += (Vector2.Reject (al, b.deltas [last]) + Vector2.Reject (localPoint - b.points [last], b.deltas [0])).normalized * darea; //nor += area += darea; } bool inCol = b.IsPointInCollider(a.gameObject.transform.position); if (count > 0 || (inCol && b.isTrigger && b.hacked)) { if (inCol) { area = a.area - area; } if (area <= 0) { area = MyMath.dFloat; } Collision s = new Collision(); s.point = b.gameObject.transform.LocalToWorldPoint(ret / area); s.normal = (ImCircle ? -1 : 1) * a.GetNormal(s.point); //s.normal = (ImCircle ? -1 : 1) * b.gameObject.transform.LocalToWorldDirection(nor / area).normalized; if (!ImCircle) { s.normal *= -1; } //Console.WriteLine ("normal " + s.normal); s.area = area; s.collider = ImCircle ? (Collider)b : (Collider)a; s.rejection = rejection; //Console.WriteLine ("Collide " + MainWindow.frameCount); //Console.WriteLine ("normal " + s.normal); return(s); } return(null); }