public void Update(GameTime gameTime) { CurrentTime = gameTime; var currentFrameBodies = Bodies.ToList(); //Update each body. foreach (var body in currentFrameBodies) { //Check if the body moved. If it did, mark as dirty and update delta position. //If not, just update its sensors. Vector2 deltaPosition = body.Speed * gameTime.ElapsedGameTime.Milliseconds; if (deltaPosition.X != 0 || deltaPosition.Y != 0) { MarkAsDirty(body, deltaPosition); } else { UpdateBodySensors(body); } //Apply gravity if not on ground. body.Speed += Gravity * body.GravityScale * gameTime.ElapsedGameTime.Milliseconds; } //Update dirty bodies. foreach (var pair in dirtyBodies) { PhysicBody body = pair.Key; Vector2 translation = pair.Value; Vector2 penetration = Vector2.Zero; //Body to tile collision. bool collided = false; if (body.IsTangible) { collided = HandleTileCollisionY(body, translation.Y, out penetration.Y); } body.Position.Y += translation.Y - penetration.Y; if (body.IsTangible) { collided |= HandleTileCollisionX(body, translation.X, out penetration.X); } body.Position.X += translation.X - penetration.X; //Tilemap collision response. if (collided) { TileMapCollisionInfo info = new TileMapCollisionInfo(); info.GameTime = CurrentTime; info.Penetration = penetration; body.TileMapCollision(info); } //Body-to-body collision testing. foreach (var other in currentFrameBodies) { collided = (body.MaskBits & other.CategoryBits) != 0 && (other.MaskBits & body.CategoryBits) != 0 && body != other && body.WorldBounds.Intersects(other.WorldBounds, out penetration); if (collided) { if (Math.Abs(penetration.X) > Math.Abs(penetration.Y)) { penetration.X = 0; } else { penetration.Y = 0; } if (body.IsTangible && other.Type == CollisionTypes.Solid) { body.Position -= penetration; if (penetration.Y * body.Speed.Y > 0) { body.Speed.Y = 0; } else if (penetration.X * body.Speed.X > 0) { body.Speed.X = 0; } BodyCollisionInfo infoOther = new BodyCollisionInfo(); infoOther.GameTime = CurrentTime; infoOther.Penetration = -penetration; infoOther.CollidingBody = body; other.BodyCollision(infoOther); } BodyCollisionInfo info = new BodyCollisionInfo(); info.GameTime = CurrentTime; info.Penetration = penetration; info.CollidingBody = other; body.BodyCollision(info); } } //Update sensors. UpdateBodySensors(body); } dirtyBodies.Clear(); //Update global sensors. foreach (var sensor in Sensors) { sensor.State = CheckSolid(sensor.Area, sensor.MaskBits, sensor.CategoryBits); } }
internal void TileMapCollision(TileMapCollisionInfo info) { TileMapCollisionEvent?.Invoke(info); }