private bool CircleLineIntersect(MovingObject o, SimpleCollidableLine boundry) { Vector2 A = boundry.From; Vector2 B = boundry.To; Vector2 C = o.Position; float r = (o.Width - 5) / 2; // approx. radius of bibble // compute the euclidean distance between A and B float lab = Vector2.Distance(A, B); // compute the direction vector D from A to B Vector2 D = new Vector2((B.X - A.X) / lab, (B.Y - A.Y) / lab); // check, whether the centre of o has passed the line within one update cycle // the object must be fast, else, in the last collision check(s) it would have // touched the line! if (Vector2.Distance(o.LastPos, o.Position) > r) // this object is fast! { Vector2 C2 = o.LastPos; float ua = (C.X - C2.X) * (A.Y - C2.Y) - (C.Y - C2.Y) * (A.X - C2.X); float ub = (B.X - A.X) * (A.Y - C2.Y) - (B.Y - A.Y) * (A.X - C2.X); float denominator = (C.Y - C2.Y) * (B.X - A.X) - (C.X - C2.X) * (B.Y - A.Y); if (Math.Abs(denominator) <= 0.00001f) { if (Math.Abs(ua) <= 0.00001f && Math.Abs(ub) <= 0.00001f && o.Collide(boundry)) { //arbitrary intersectionpoint // (A + B) / 2; return true; } } else { ua /= denominator; ub /= denominator; if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) { // crossing point E Vector2 Es = new Vector2(A.X + ua * (B.X - A.X), A.Y + ua * (B.Y - A.Y)); // compute the euclidean distance from E to C float lecs = (float)Math.Sqrt((Es.X - C.X) * (Es.X - C.X) + (Es.Y - C.Y) * (Es.Y - C.Y)); //intersectionPoint.X = A.X + ua * (B.X - A.X); //intersectionPoint.Y = A.Y + ua * (B.Y - A.Y); if (o.Collide(boundry)) { o.Position = Es; return true; } else { //position and orientation correction Vector2 resulting; Vector2 oldDirection = new Vector2((float)Math.Cos(o.MovementDirection), (float)Math.Sin(o.MovementDirection)); Vector2 normal = new Vector2(-D.Y, D.X); Vector2.Reflect(ref oldDirection, ref normal, out resulting); if (resulting.Length() != 1f) { resulting.Normalize(); } o.MovementDirection = (float)Math.Atan2(resulting.Y, resulting.X); // move it back distance r-lec and furth r-lec again (in the new direction) o.Position = Es + resulting * lecs; return false; } } } } if (Vector2.Distance(A, C) + Vector2.Distance(B, C) - 2 * r > lab) { return false; } // Now the line equation is x = Dx*t + Ax, y = Dy*t + Ay with 0 <= t <= 1. // compute the value t of the closest point to the circle center (Cx, Cy) float t = D.X * (C.X - A.X) + D.Y * (C.Y - A.Y); // This is the projection of C on the line from A to B. // compute the coordinates of the point E on line and closest to C Vector2 E = new Vector2(t * D.X + A.X, t * D.Y + A.Y); // compute the euclidean distance from E to C float lec = (float)Math.Sqrt((E.X - C.X) * (E.X - C.X) + (E.Y - C.Y) * (E.Y - C.Y)); // test if the line intersects or tangents the circle if (lec < r) // TODO lec = r { /* // compute distance from t to circle intersection point float dt = (float)Math.Sqrt(r * r - lec * lec); // compute first intersection point Vector2 F = new Vector2((t - dt) * D.X + A.X, (t - dt) * D.Y + A.Y); // compute second intersection point Vector2 G = new Vector2((t + dt) * D.X + A.X, (t + dt) * D.Y + A.Y);*/ if (o.Collide(boundry)) { Explosion(E, 0.05f, false); // ugly style return true; } else { Vector2 resulting; Vector2 oldDirection = new Vector2((float)Math.Cos(o.MovementDirection), (float)Math.Sin(o.MovementDirection)); if (Vector2.Distance(C - oldDirection, E) < Vector2.Distance(C + oldDirection, E)) return false; Vector2 normal = new Vector2(-D.Y, D.X); Vector2.Reflect(ref oldDirection, ref normal, out resulting); if (resulting.Length() != 1f) { resulting.Normalize(); } o.MovementDirection = (float)Math.Atan2(resulting.Y, resulting.X); // move it back distance r-lec and furth r-lec again (in the new direction) o.Position -= oldDirection * (r - lec); o.Position += resulting * (r - lec); return false; } } else { // line doesn't touch circle return false; } }
internal void addLine(SimpleCollidableLine l) { lines.Add(l); Components.Add(l); }