public static List <AbstractGameObject> ProcessFrame(GameTime gameTime, List <AbstractGameObject> collidables, GameGrid grid) { float percentCompleted = 0; List <Tuple <float, Side, AbstractGameObject, AbstractGameObject> > completedCollisions = new List <Tuple <float, Side, AbstractGameObject, AbstractGameObject> >(); List <AbstractGameObject> removedGameObjects = new List <AbstractGameObject>(); while (percentCompleted < 1) { List <AbstractGameObject> neighbours = new List <AbstractGameObject>(); List <Tuple <float, Side, AbstractGameObject, AbstractGameObject> > collisions = new List <Tuple <float, Side, AbstractGameObject, AbstractGameObject> >(); foreach (AbstractGameObject obj in collidables) { if (obj.BoundingBox == null) { continue; } neighbours = grid.FindNeighbours(obj); foreach (AbstractGameObject neighbour in neighbours) { if (neighbour.BoundingBox == null) { continue; } if (collided(obj, neighbour)) { Side side = Side.None; float percent = WhenCollisionCheck(obj, neighbour, percentCompleted, out side); if (!(obj is AbstractBlock && neighbour is AbstractBlock)) { if (!(obj is Mario && neighbour is HiddenBrickObject) || ((obj is Mario && neighbour is HiddenBrickObject) && !neighbour.Visible && obj.BoundingBox.Dimensions.Top >= neighbour.BoundingBox.Dimensions.Bottom)) { collisions.Add(new Tuple <float, Side, AbstractGameObject, AbstractGameObject>(percent, side, obj, neighbour)); } else if ((obj is HiddenBrickObject && obj.Visible) || (neighbour is HiddenBrickObject && neighbour.Visible)) { collisions.Add(new Tuple <float, Side, AbstractGameObject, AbstractGameObject>(percent, side, obj, neighbour)); } } } } } float earliestCollisionPercent; if (collisions.Count == 0) { earliestCollisionPercent = 1; } else { collisions.Sort((x, y) => (x.Item1.CompareTo(y.Item1))); filterCollisions(completedCollisions, collisions, out earliestCollisionPercent); } if ((earliestCollisionPercent - percentCompleted) != 0) { int numRemoved = 1; while (numRemoved != 0) { removedGameObjects.AddRange(UpdateObjects(collidables, grid, gameTime, earliestCollisionPercent - percentCompleted)); percentCompleted += (earliestCollisionPercent - percentCompleted); collidables.RemoveAll((x) => removedGameObjects.Contains(x)); numRemoved = collisions.RemoveAll((x) => (removedGameObjects.Contains(x.Item3) || removedGameObjects.Contains(x.Item4))); filterCollisions(completedCollisions, collisions, out earliestCollisionPercent); collisions.Sort((x, y) => (x.Item1.CompareTo(y.Item1))); } } bool anySignificantCollision = false; for (int i = 0; i < collisions.Count && collisions[i].Item1 == earliestCollisionPercent; i++) { Tuple <float, Side, AbstractGameObject, AbstractGameObject> collision = collisions[i]; Side side = collision.Item2; AbstractGameObject obj1 = collision.Item3; AbstractGameObject obj2 = collision.Item4; anySignificantCollision = true; if (obj2 is Mario) { obj2.CollisionResponse(obj1, GetOppositeSide(side), gameTime); obj1.CollisionResponse(obj2, side, gameTime); } else { obj1.CollisionResponse(obj2, side, gameTime); obj2.CollisionResponse(obj1, GetOppositeSide(side), gameTime); } if (obj1.BoundingBox != null) { if ((obj2.BoundingBox != null) && !(obj1 is AbstractBlock || obj1 is CoinObject || obj1 is FireFlowerObject) && (obj2 is AbstractEnemy || (obj2 is AbstractBlock && obj2.Visible))) { if (RectangleSidesTouching(obj1.BoundingBox.Dimensions, obj2.BoundingBox.Dimensions) || obj1.BoundingBox.Dimensions.Intersects(obj2.BoundingBox.Dimensions)) { obj1.FixClipping(FindClippingCorrection(obj1, obj2), obj1, obj2); } } } if (obj2.BoundingBox != null) { if ((obj1.BoundingBox != null) && !(obj2 is AbstractBlock || obj2 is CoinObject || obj2 is FireFlowerObject) && (obj1 is AbstractEnemy || (obj1 is AbstractBlock && obj1.Visible))) { if (RectangleSidesTouching(obj2.BoundingBox.Dimensions, obj1.BoundingBox.Dimensions) || (obj2.BoundingBox.Dimensions.Intersects(obj1.BoundingBox.Dimensions))) { obj2.FixClipping(FindClippingCorrection(obj2, obj1), obj1, obj2); } } } completedCollisions.Add(collision); } if (!anySignificantCollision && !(earliestCollisionPercent == 1)) { earliestCollisionPercent = 1; removedGameObjects.AddRange(UpdateObjects(collidables, grid, gameTime, earliestCollisionPercent - percentCompleted)); collidables.RemoveAll((x) => removedGameObjects.Contains(x)); } percentCompleted += (earliestCollisionPercent - percentCompleted); } return(removedGameObjects); }
private static List <AbstractGameObject> UpdateObjects(List <AbstractGameObject> objects, GameGrid grid, GameTime gameTime, float percentToUpdate) { var removed = new List <AbstractGameObject>(); foreach (AbstractGameObject obj in objects) { HitBox oldHitbox = (obj.BoundingBox != null) ? new HitBox(obj.BoundingBox) : null; if (obj.Update(gameTime, percentToUpdate)) { removed.Add(obj); } if (oldHitbox != null && obj.BoundingBox != null) { grid.UpdateObjectGridPosition(obj, oldHitbox); } } return(removed); }