示例#1
0
        public static Edge GetNearestEdge(this TmxLayerTile self, int worldPosition)
        {
            var tileWidth = self.Tileset.Map.TileWidth;
            var tileMiddleWorldPosition = self.X * tileWidth + tileWidth / 2;

            return(worldPosition < tileMiddleWorldPosition ? Edge.Left : Edge.Right);
        }
示例#2
0
        /// <summary>
        /// sets the tile and updates its tileset. If you change a tiles gid to one in a different Tileset you must
        /// call this method or update the TmxLayerTile.tileset manually!
        /// </summary>
        /// <returns>The tile.</returns>
        /// <param name="tile">Tile.</param>
        public TmxLayerTile SetTile(TmxLayerTile tile)
        {
            Tiles[tile.X + tile.Y * Width] = tile;
            tile.Tileset = Map.GetTilesetForTileGid(tile.Gid);

            return(tile);
        }
示例#3
0
        public static Edge GetHighestSlopeEdge(this TmxLayerTile self)
        {
            // left and right already have flipping taken into account. Also remember a lower value means a taller slope since the slope values
            // are in pixels from the top!
            var left  = self.GetSlopeTopLeft();
            var right = self.GetSlopeTopRight();

            return(right > left ? Edge.Left : Edge.Right);
        }
示例#4
0
        public static int GetSlopeTopRight(this TmxLayerTile self)
        {
            if (self.HorizontalFlip && self.VerticalFlip)
            {
                return(self.TilesetTile.SlopeTopRight);
            }
            if (self.HorizontalFlip)
            {
                return(self.TilesetTile.SlopeTopLeft);
            }
            if (self.VerticalFlip)
            {
                return(self.Tileset.Map.TileWidth - self.TilesetTile.SlopeTopRight);
            }

            return(self.TilesetTile.SlopeTopRight);
        }
示例#5
0
        public static float GetSlope(this TmxLayerTile self)
        {
            var tileSize = self.Tileset.Map.TileWidth;

            // flip our slopes sign if the tile is flipped horizontally or vertically
            if (self.HorizontalFlip)
            {
                tileSize *= -1;
            }

            if (self.VerticalFlip)
            {
                tileSize *= -1;
            }

            // rise over run
            return((self.TilesetTile.SlopeTopRight - (float)self.TilesetTile.SlopeTopLeft) / tileSize);
        }
示例#6
0
 public static float GetSlopeOffset(this TmxLayerTile self) => self.GetSlopeTopLeft();
示例#7
0
 public static bool IsOneWayPlatform(this TmxLayerTile self) => self.TilesetTile != null && self.TilesetTile.IsOneWayPlatform;
示例#8
0
 public static bool IsSlope(this TmxLayerTile self) => self.TilesetTile != null && self.TilesetTile.IsSlope;
示例#9
0
 public void ClearLastGroundTile() => _lastGroundTile = null;
示例#10
0
        /// <summary>
        /// Tests the tile for a collision. Returns via out the position in world space where the collision occured.
        /// </summary>
        /// <returns>The tile collision.</returns>
        /// <param name="tile">Tile.</param>
        /// <param name="edgeToTest">the opposite side of movement, the side the leading edge will collide with</param>
        /// <param name="perpindicularPosition">Perpindicular position.</param>
        /// <param name="leadingPosition">Leading position.</param>
        /// <param name="shouldTestSlopes">Should test slopes.</param>
        /// <param name="collisionResponse">Collision response.</param>
        bool TestTileCollision(TmxLayerTile tile, Edge edgeToTest, int perpindicularPosition, int leadingPosition,
                               bool shouldTestSlopes, out int collisionResponse)
        {
            collisionResponse = leadingPosition;

            // one way platforms are only collideable from the top when the player is already above them
            if (tile.IsOneWayPlatform())
            {
                // only the top edge of one way platforms are checked for collisions
                if (edgeToTest != Edge.Top)
                {
                    return(false);
                }

                // our response should be the top of the platform
                collisionResponse = TiledMap.TileToWorldPositionX(tile.Y);
                return(_boxColliderBounds.Bottom <= collisionResponse);
            }

            var forceSlopedTileCheckAsWall = false;

            // when moving horizontally the only time a slope is considered for collision testing is when its closest side is the tallest side
            // and we were not intesecting the tile before moving.
            // this prevents clipping through a tile when hitting its edge: -> |\
            if (edgeToTest.IsHorizontal() && tile.IsSlope() &&
                tile.GetNearestEdge(leadingPosition) == tile.GetHighestSlopeEdge())
            {
                var moveDir = edgeToTest.OppositeEdge();
                var leadingPositionPreMovement = _boxColliderBounds.GetSide(moveDir);

                // we need the tile x position that is on the opposite side of our move direction. Moving right we want the left edge
                var tileX = moveDir == Edge.Right
                                        ? TiledMap.TileToWorldPositionX(tile.X)
                                        : TiledMap.TileToWorldPositionX(tile.X + 1);

                // using the edge before movement, we see if we were colliding before moving.
                var wasCollidingBeforeMove = moveDir == Edge.Right
                                        ? leadingPositionPreMovement > tileX
                                        : leadingPositionPreMovement < tileX;

                // if we were not colliding before moving we need to consider this tile for a collision check as if it were a wall tile
                forceSlopedTileCheckAsWall = !wasCollidingBeforeMove;
            }


            if (forceSlopedTileCheckAsWall || !tile.IsSlope())
            {
                switch (edgeToTest)
                {
                case Edge.Top:
                    collisionResponse = TiledMap.TileToWorldPositionY(tile.Y);
                    break;

                case Edge.Bottom:
                    collisionResponse = TiledMap.TileToWorldPositionY(tile.Y + 1);
                    break;

                case Edge.Left:
                    collisionResponse = TiledMap.TileToWorldPositionX(tile.X);
                    break;

                case Edge.Right:
                    collisionResponse = TiledMap.TileToWorldPositionX(tile.X + 1);
                    break;
                }

                return(true);
            }

            if (shouldTestSlopes)
            {
                var tileWorldX = TiledMap.TileToWorldPositionX(tile.X);
                var tileWorldY = TiledMap.TileToWorldPositionX(tile.Y);
                var slope      = tile.GetSlope();
                var offset     = tile.GetSlopeOffset();

                // calculate the point on the slope at perpindicularPosition
                collisionResponse = (int)(edgeToTest.IsVertical()
                                        ? slope * (perpindicularPosition - tileWorldX) + offset + tileWorldY
                                        : (perpindicularPosition - tileWorldY - offset) / slope + tileWorldX);
                var isColliding = edgeToTest.IsMax()
                                        ? leadingPosition <= collisionResponse
                                        : leadingPosition >= collisionResponse;

                // this code ensures that we dont consider collisions on a slope while jumping up that dont intersect our collider.
                // It also makes sure when testing the bottom edge that the leadingPosition is actually above the collisionResponse.
                // HACK: It isn't totally perfect but it does the job
                if (isColliding && edgeToTest == Edge.Bottom && leadingPosition <= collisionResponse)
                {
                    isColliding = false;
                }

                return(isColliding);
            }

            return(false);
        }