/// <summary> /// Instantiates a player, puts him in the level, and remembers where to put him when he is resurrected. /// </summary> private Tile LoadStartTile(int x, int y) { if (Player != null) { throw new NotSupportedException("A level may only have one starting point."); } start = RectangleExtensions.GetBottomCenter(GetBounds(x, y)); player = new Player(this, start); return(new Tile(null, TileCollision.Passable, TileMovement.Static)); }
/// <summary> /// Moves the platform along a path, waiting at either end. /// </summary> public void Update(GameTime gameTime) { bool mustmove = true; // Get the bounding rectangle and find neighboring tiles. Rectangle 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; // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { for (int x = leftTile; x <= rightTile; ++x) { // If this tile is collidable, TileCollision collision = Level.GetCollision(x, y); if (collision != TileCollision.Passable) { // Determine collision depth (with direction) and magnitude. Rectangle tileBounds = Level.GetBounds(x, y); Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); if (depth != Vector2.Zero) { float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; direction = (FaceDirection)(-(int)direction); if (glidermovement == TileMovement.Vertical) { Position = new Vector2(Position.X, Position.Y + depth.Y); } else if (glidermovement == TileMovement.Horizontal) { Position = new Vector2(Position.X + depth.X, Position.Y); } mustmove = false; break; } } } if (!mustmove) { break; } } if (mustmove) { float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; if (position.Y < 0.0f - bounds.Height) { position = new Vector2(position.X, (level.Height * Tile.Height) + bounds.Height); } else if (position.Y > (level.Height * Tile.Height) + bounds.Height) { position = new Vector2(position.X, 0.0f); } else { if (glidermovement == TileMovement.Vertical) { Vector2 velocity = new Vector2(0.0f, (int)direction * moveSpeed * elapsed); position = position + velocity; } else if (glidermovement == TileMovement.Horizontal) { Vector2 velocity = new Vector2((int)direction * moveSpeed * elapsed, 0.0f); position = position + velocity; } } } }
/// <summary> /// Detects and resolves collisions between the Player and the glidingPlatform nearest him. /// </summary> public void HandleGlidingPlatformCollisions() { // Did I just collide with a gliding platform? foreach (GlidingPlatform platform in Level.playerPlatforms) // To know this we have to check the list of platforms in // the camera's visible range // which we collected from the level calss { // We check if the player's feet intersect with the platform's surface. if (platform.Surface.Intersects(Feet)) { OnPlatform(platform); // If so, then this is the platform we want to save. } } // If I own a platform if (isOnPlatform == true) { // reset isOnPlatform for the purposes of evaluating it again. isOnPlatform = false; // Do they intersect? if (Feet.Intersects(platform.Surface)) { isOnPlatform = true; //Yes they intersect. By how deep? Vector2 depth = RectangleExtensions.GetIntersectionDepth(Feet, platform.Surface); // Is it more than zero? if (depth != Vector2.Zero) { // Yes they intersect and it is more than zero depth! // Find out by how much. float absDepthX = Math.Abs(depth.X); float absDepthY = Math.Abs(depth.Y); // Act as if we are on the ground if we were previously on the a platform. if (previousBottom >= platform.Surface.Top) { isOnGround = true; } if (isOnPlatform) { // Resolve the collision along the Y axis. Position = new Vector2(Position.X /*+ platform.Position.X*/, Position.Y - Math.Abs(depth.Y)); } } } } // Check if the player's Y has moved through a platform's surface. foreach (GlidingPlatform platform in level.playerPlatforms) { if ((position.Y > platform.Surface.Top - 12) && (position.Y < platform.Surface.Top + 12) && (position.X > platform.Surface.Left - BoundingRectangle.Width / 2) && (position.X < platform.Surface.Right + BoundingRectangle.Width / 2) && (velocity.Y > 0)) // if the velocity is negative the player is jumping up. // If the player is jumping up, we don't want him to stick, only when moving down. // The speed the player moves with a MaxFallSpeed of 600.0f is 12 pixels per second. // If we don't check this condition, the player can jump right past the surface of the platform, // and the game will never know to make the player stick! { OnPlatform(platform); position.Y = platform.Surface.Top; } } previousBottom = BoundingRectangle.Bottom; }
/// <summary> /// Detects and resolves all collisions between the player and his neighboring /// tiles. When a collision is detected, the player is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> private void HandleCollisions() { // Get the player's bounding rectangle and find neighboring tiles. Rectangle 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; // Reset flag to search for ground collision. isOnGround = false; // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { for (int x = leftTile; x <= rightTile; ++x) { // If this tile is collidable, TileCollision collision = Level.GetCollision(x, y); if (collision != TileCollision.Passable) { // Determine collision depth (with direction) and magnitude. Rectangle tileBounds = Level.GetBounds(x, y); 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 (absDepthY < absDepthX || collision == TileCollision.Platform) { // If we crossed the top of a tile, we are on the ground. if (previousBottom <= tileBounds.Top) { isOnGround = 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; } } } } } // Save the new bounds bottom. // previousBottom = bounds.Bottom; }