public void Translate(PhysicBody body, Vector2 translation) { if (translation.X != 0 || translation.Y != 0) { MarkAsDirty(body, translation); } }
private void UpdateBodySensors(PhysicBody body) { foreach (var sensor in body.Sensors) { Rectangle worldArea = sensor.Area; worldArea.Offset(body.Position); worldArea.Offset(body.Bounds.Location); sensor.State = CheckSolid(worldArea, sensor.MaskBits, sensor.CategoryBits); } }
private void MarkAsDirty(PhysicBody body, Vector2 deltaPosition) { if (dirtyBodies.ContainsKey(body)) { dirtyBodies[body] += deltaPosition; if (deltaPosition.X == 0 && deltaPosition.Y == 0) { dirtyBodies.Remove(body); } } else { dirtyBodies.Add(body, deltaPosition); } }
private bool HandleTileCollisionY(PhysicBody body, float deltaY, out float penetration) { bool collided = false; penetration = 0; if (deltaY > 0) { int floorY; if (Tiles.QueryFloor(body.WorldBounds, out floorY)) { int bottom = (int)Tiles.GetWorldY(floorY); int bodyBottom = (int)(body.Position.Y + body.Bounds.Bottom); if (bottom <= deltaY + bodyBottom) { collided = true; penetration = deltaY + bodyBottom - bottom; if (body.Speed.Y > 0) { body.Speed.Y = 0; } } } } else if (deltaY < 0) { int ceilingY; if (Tiles.QueryCeiling(body.WorldBounds, out ceilingY)) { int top = (int)Tiles.GetWorldY(ceilingY) + Tile.Height; int bodyTop = (int)body.Position.Y + body.Bounds.Top; if (top > deltaY + bodyTop) { collided = true; penetration = deltaY + bodyTop - top; if (body.Speed.Y < 0) { body.Speed.Y = 0; } } } } return(collided); }
private bool HandleTileCollisionX(PhysicBody body, float deltaX, out float penetration) { bool collided = false; penetration = 0; if (deltaX > 0) { int wallX; if (Tiles.QueryWallRight(body.WorldBounds, out wallX)) { int rightWall = (int)Tiles.GetWorldX(wallX); int bodyRight = (int)body.Position.X + body.Bounds.Right; if (rightWall < deltaX + bodyRight) { collided = true; penetration = deltaX + bodyRight - rightWall; if (body.Speed.X > 0) { body.Speed.X = 0; } } } } else if (deltaX < 0) { int wallX; if (Tiles.QueryWallLeft(body.WorldBounds, out wallX)) { int leftWall = (int)Tiles.GetWorldX(wallX) + Tile.Width; int bodyLeft = (int)body.Position.X + body.Bounds.Left; if (leftWall > deltaX + bodyLeft) { collided = true; penetration = deltaX + bodyLeft - leftWall; if (body.Speed.X > 0) { body.Speed.X = 0; } } } } return(collided); }
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); } }