Nez.Portable/ECS/Components/Physics/TiledMapMover.cs
/// <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>
Tests the tile for a collision. Returns via out the position in world space where the collision occured.
Tests the tile for a collision . Returns via out the position in world space where the collision occured .
bool testTileCollision(
            TiledTile tile,
            Edge edgeToTest,
            int perpindicularPosition,
            int leadingPosition,
            bool shouldTestSlopes,
            out int collisionResponse)
        {
            collisionResponse = leadingPosition;
            if (tile.isOneWayPlatform())
            {
                if (edgeToTest != Edge.Top)
                    return false;
                collisionResponse = tiledMap.tileToWorldPositionX(tile.y);
                return _boxColliderBounds.Bottom <= collisionResponse;
            }
            var forceSlopedTileCheckAsWall = false;
            if (edgeToTest.isHorizontal() && tile.isSlope()
                                          && tile.getNearestEdge(leadingPosition) == tile.getHighestSlopeEdge())
            {
                var moveDir = edgeToTest.oppositeEdge();
                var leadingPositionPreMovement = _boxColliderBounds.getSide(moveDir);
                var tileX = moveDir == Edge.Right
                                ? tiledMap.tileToWorldPositionX(tile.x)
                                : tiledMap.tileToWorldPositionX(tile.x + 1);
                var wasCollidingBeforeMove = moveDir == Edge.Right
                                                 ? leadingPositionPreMovement > tileX
                                                 : leadingPositionPreMovement < tileX;
                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();
                collisionResponse = (int)(edgeToTest.isVertical()
                                              ? slope * (perpindicularPosition - tileWorldX) + offset + tileWorldY
                                              : (perpindicularPosition - tileWorldY - offset) / slope + tileWorldX);
                var isColliding = edgeToTest.isMax()
                                      ? leadingPosition <= collisionResponse
                                      : leadingPosition >= collisionResponse;
                if (isColliding && edgeToTest == Edge.Bottom && leadingPosition <= collisionResponse)
                    isColliding = false;
                return isColliding;
            }
            return false;
        }
bool testTileCollision ( TiledTile tile , Edge edgeToTest , int perpindicularPosition , int leadingPosition , bool shouldTestSlopes , out int collisionResponse ) { collisionResponse = leadingPosition ; if ( tile . isOneWayPlatform ( ) ) { if ( edgeToTest != Edge . Top ) return false ; collisionResponse = tiledMap . tileToWorldPositionX ( tile . y ) ; return _boxColliderBounds . Bottom <= collisionResponse ; } var forceSlopedTileCheckAsWall = false ; if ( edgeToTest . isHorizontal ( ) && tile . isSlope ( ) && tile . getNearestEdge ( leadingPosition ) == tile . getHighestSlopeEdge ( ) ) { var moveDir = edgeToTest . oppositeEdge ( ) ; var leadingPositionPreMovement = _boxColliderBounds . getSide ( moveDir ) ; var tileX = moveDir == Edge . Right ? tiledMap . tileToWorldPositionX ( tile . x ) : tiledMap . tileToWorldPositionX ( tile . x + 1 ) ; var wasCollidingBeforeMove = moveDir == Edge . Right ? leadingPositionPreMovement > tileX : leadingPositionPreMovement < tileX ; 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 ( ) ; collisionResponse = ( int ) ( edgeToTest . isVertical ( ) ? slope * ( perpindicularPosition - tileWorldX ) + offset + tileWorldY : ( perpindicularPosition - tileWorldY - offset ) / slope + tileWorldX ) ; var isColliding = edgeToTest . isMax ( ) ? leadingPosition <= collisionResponse : leadingPosition >= collisionResponse ; if ( isColliding && edgeToTest == Edge . Bottom && leadingPosition <= collisionResponse ) isColliding = false ; return isColliding ; } return false ; }
Tests the tile for a collision.
Tests the tile for a collision .
// one way platforms are only collideable from the top when the player is already above them // only the top edge of one way platforms are checked for collisions // our response should be the top of the platform // 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: -> |\ // we need the tile x position that is on the opposite side of our move direction. Moving right we want the left edge // using the edge before movement, we see if we were colliding before moving. // if we were not colliding before moving we need to consider this tile for a collision check as if it were a wall tile // calculate the point on the slope at perpindicularPosition // 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
The tile collision.
The tile collision .
tile
TiledTile
None
edgeToTest
Edge
the opposite side of movement, the side the leading edge will collide with
the opposite side of movement the side the leading edge will collide with
perpindicularPosition
int
None
leadingPosition
int
None
shouldTestSlopes
bool
Should test slopes.
Should test slopes .
int
out
collisionResponse
None