private void CalculateActorsCollisions(double dt) { if (Actors.Count == 1) { return; } Dictionary <Actor, List <Actor> > actorsToUnite = new Dictionary <Actor, List <Actor> >(); foreach (var actor1 in Actors) { foreach (var actor2 in Actors) { if (actor1.Id < actor2.Id && Box2.Overlap(actor1.Box, actor2.Box)) { var collision = actor1.Box.CalcualteCollision(dt * (actor1.Velocity - actor2.Velocity), actor2.Box); if (collision.IsNone) { continue; } bool isXCollision = collision.Vector.X != 0; if (actor1.Size == actor2.Size && actor1.Orientation == actor2.Orientation) { var size = actor1.Size; var orientation = actor1.Orientation; var midpoint = actor1.Location + (actor2.Location - actor1.Location) / 2; if (isXCollision && orientation != ActorOrientation.FLAT) { actorsToUnite.Add(new Actor(this, midpoint) { Orientation = orientation == ActorOrientation.TALL ? ActorOrientation.SQUARE : ActorOrientation.FLAT, Size = orientation == ActorOrientation.TALL ? size * 2 : size, }, new List <Actor> { actor1, actor2 }); continue; } else if (!isXCollision && orientation != ActorOrientation.TALL) { actorsToUnite.Add(new Actor(this, new Point2(midpoint.X, Math.Min(actor1.Location.Y, actor2.Location.Y))) { Orientation = orientation == ActorOrientation.FLAT ? ActorOrientation.SQUARE : ActorOrientation.TALL, Size = orientation == ActorOrientation.FLAT ? size * 2 : size, }, new List <Actor> { actor1, actor2 }); continue; } } var unit = isXCollision ? Vector2.X_UNIT : Vector2.Y_UNIT; var m1 = actor1.Mass; var m2 = actor2.Mass; var v1 = actor1.Velocity * unit; var v2 = actor2.Velocity * unit; var u2 = (2 * m1 * v1 + v2 * (m2 - m1)) / (m1 + m2); var u1 = u2 + v2 - v1; actor1.Velocity += unit * (u1 - v1); actor2.Velocity += unit * (u2 - v2); //todo: this is definitely wrong actor1.Location -= collision.Vector / 2; actor2.Location += collision.Vector / 2; } } } foreach (var item in actorsToUnite) { foreach (var oldActor in item.Value) { Actors.Remove(oldActor); } Actors.Add(item.Key); OnActorUnion?.Invoke(item.Key); } }
Munch LocateOverlappingMunch(Actor actor) => Munches.FirstOrDefault(munch => Box2.Overlap(munch.Box, actor.Box));