private void HandleCollisions()
{
// Get the player's bounding rectangle and find neighboring tiles.
RectangleF bounds = BoundingRectangle;
int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;
List<Tile> candidateTiles = new List<Tile>();
for (int y = topTile; y <= bottomTile; ++y)
{
for (int x = leftTile; x <= rightTile; ++x)
{
Tile tile = level.getTile(x, y);
candidateTiles.Add(tile);
}
}
candidateTiles.AddRange(level.MoveableTiles);
// Reset flag to search for ground collision.
isOnGround = false;
bool movedByTile = false; // Ensure only none tile can move the player at a time
// For each potentially colliding tile,
foreach(Tile tile in candidateTiles)
{
if (tile == null)
continue;
// If this tile is collidable,
TileCollision collision = tile.Collision;
if (collision != TileCollision.Passable)
{
// Determine collision depth (with direction) and magnitude.
RectangleF tileBounds = tile.Sprite.Bounds;
Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
// Resolve the collision along the shallow axis.
if (collision != TileCollision.Death && collision != TileCollision.Water && collision != TileCollision.Ladder && (absDepthY < absDepthX || collision == TileCollision.Platform))
{
// If we crossed the top of a tile, we are on the ground.
// This needs to change for ladder mechanic
//if (previousBottom <= tileBounds.Top)
if(tileBounds.Top - previousBottom < 0.001f) // 0.001 is the delta for floating point comparisons
{
isOnGround = true;
isClimbing = false;
isJumping = false;
}
// Perform moving tile collition
if (tile is MoveableTile && !movedByTile)
{
MoveableTile moveableTile = (MoveableTile)tile;
position += moveableTile.FrameVelocity;
isOnGround = true;
movedByTile = true;
}
// Ignore platforms, unless we are on the ground.
if (collision == TileCollision.Impassable || IsOnGround)
{
// Resolve the collision along the Y axis.
Position = new Vector2(Position.X, Position.Y + depth.Y);
// Perform further collisions with the new bounds.
bounds = BoundingRectangle;
}
}
else if (collision == TileCollision.Impassable) // Ignore platforms.
{
// Resolve the collision along the X axis.
Position = new Vector2(Position.X + depth.X, Position.Y);
// Perform further collisions with the new bounds.
bounds = BoundingRectangle;
}
else if (isAlive && collision == TileCollision.Ladder && !isClimbing)
{
//when we are walking in front of a ladder, or falling past a ladder
isClimbing = true;
// Resolve the collision along the Y axis
Position = new Vector2(Position.X, Position.Y);
// Future collisions with the new bounds
bounds = BoundingRectangle;
}
else if (isAlive && collision == TileCollision.Death) // Something that kills you!
{
if(absDepthY > tile.Sprite.Height/2)
OnKilled("You touched something stupid!", DeathType.Spike);
}
else if (isAlive && collision == TileCollision.Water)
{
RectangleF tileRect = tile.Sprite.Bounds;
RectangleF headRect = BoundingRectangle;
headRect.Height /= 8; // Take the bounds of the head only
if (tileRect.Intersects(headRect))
OnKilled("You drowned under water", DeathType.Water);
}
}
}
}
// Save the new bounds bottom.
previousBottom = bounds.Bottom;
}